代码之家  ›  专栏  ›  技术社区  ›  Enlico

函数monad真的提供了比函数applicative functor更多的东西吗?如果是,什么?

  •  0
  • Enlico  · 技术社区  · 4 年前

    对于monad函数,我发现 (<*>) (>>=) / (=<<) 有两种惊人相似的类型。特别地, (=<<) 使相似性更加明显:

    (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
    (=<<) :: (a -> r -> b) -> (r -> a) -> (r -> b)
    

    所以两者都一样 (<*>) (>>=) / (=<<) 取一个二元函数和一元函数 constrain 前者的两个论点中的一个有待通过后者从另一个论点中确定。毕竟,我们知道对于函数applicative/monad,

    f <*> g = \x -> f x (g x)
    f =<< g = \x -> f (g x) x 
    

    它们看起来如此惊人地相似(或者对称,如果你想的话),以至于我忍不住想到了标题中的问题。

    关于单子比应用函子“更强大”的问题,在 LYAH's For a Few Monads More chapter ,声明如下:

    […] join 不能仅使用函子和应用程序提供的函数来实现。

    参加 无法在以下方面实施: (<*>) , pure fmap .

    但是,这件事呢 作用 我上面提到的适用/蒙达?

    我知道 join === (>>= id) ,对于函数monad,它可以归结为 \f x -> f x x ,即通过将后者的一个参数作为前者的两个参数输入,使二元函数成为一元函数。

    我能用英语表达吗 (<*>) ? 嗯,实际上我想我可以:不是吗 flip ($) <*> f === join f 对的不是吗 flip ($) <*> f 实现 参加 而没有 (>>=) / (=<<) return ?

    然而,考虑到列表applicative/monad,我可以表示 参加 没有明确使用 (=<<) / (>>=) 回来 (甚至没有 (<*>) ,fwiw): join = concat ; 所以很可能还有实施 join f = flip ($) <*> f 如果我仅仅依靠 Applicative 或者也在 Monad .

    0 回复  |  直到 4 年前
        1
  •  21
  •   Fyodor Soikin    4 年前

    当你实施 join 这样,你使用的函数类型知识超出了 Applicative 给你。这种知识被编码在语言的使用中 ($) 这就是“应用”操作符,它甚至是函数的核心。同样的事情也会发生在你的列表中,例如:你正在使用 concat ,这是基于对列表性质的了解。

    一般来说,如果你能使用特定单子的知识,你就可以表达任何幂的计算。例如 Maybe 你可以匹配它的构造函数,然后用这种方式表达任何东西。当LYAH说单子比应用更强大时,它的意思是“作为抽象”,不适用于任何特定的单子。

        2
  •  2
  •   Will Ness Derri Leahy    4 年前

    编辑2: 这个问题的问题是它很模糊。它使用了一个根本没有定义的概念(“更强大”),让读者猜测它的含义。因此,我们只能得到毫无意义的答案。当然,任何东西都可以在使用Haskell的所有武器库时进行编码。这是一个空洞的说法。这不是问题所在。

    据我所知,一个明确的问题是:分别使用Monad/Applicative/Functor中的方法作为 原语 ,而完全不使用显式模式匹配,是一类计算,因此对于使用中的一组或另一组原语,可以严格地表示为更大的计算。现在 可以得到有意义的回答。

    不过,函数是不透明的。无论如何都不存在模式匹配。如果不限制我们可以使用什么,这个问题同样没有意义。然后,限制就变成了,显式使用命名参数,有意义的编程风格,因此我们只允许自己以组合方式编码。

    那么,对于列表 fmap app ( <*> )只是,我们有太多的计算可以表达,而且 join 对我们的武器库来说,这确实让它变得更大。但函数却不是这样。 join = W = CSI = flip app id .结束。

    实施 app f g x = (f x) (g x) = id (f x) (g x) :: (->) r (a->b) -> (->) r a -> (->) r b ,我已经有了 flip app id :: (->) r (r->b) -> (->) r b ,我不妨称之为 参加 因为这个型号很合适。不管我写不写,它都已经存在了。另一方面 app fs xs :: [] (a->b) -> [] a -> [] b ,我好像没办法 [] ([] b) -> [] b 二者都 -> 她在吗 (->) r (a->b) 是吗 相同的 ; 功能 special .

    (顺便说一句,我现在不知道如何 密码 名单是 应用程序 明确地 没有真正编码 参加 也使用列表理解等同于使用 concat ; 和 海螺 实施 参加 信息技术 参加 ).


    join f = f <*> id
    

    这很简单,所以毫无疑问。


    ( 编辑: 嗯,显然还有疑问)。

    (=<<) = (<*>) . flip 功能。就这样。这意味着对于函数Monad和Applicative Functor是一样的。 flip 是一个普遍适用的组合词。 海螺 不是。当然,这和函数有某种融合。但这里没有具体的函数(比如 海螺 是一个特定的函数),或任何地方,因为函数是不透明的。

    作为一种特殊的数据类型,它可以进行模式匹配。作为单子,虽然它只知道 >>= return . 海螺 确实使用模式匹配来完成工作。 id 没有。

    身份证件 这里类似于列表 [] 海螺 它的有效性正是它的意思,即被视为应用函子或单子的函数是相同的。当然,总的来说,Monad的功能大于应用,但这不是问题所在。如果你能表达 参加 对于带有 <*> [] ,我认为这意味着它们对列表也有同样的能力。

    在里面 (=<<)=(<*>)。轻弹 二者都 轻弹 (.) 什么也不做 它们被应用到的功能。所以他们对这些函数的内部结构一无所知。喜欢 foo = foldr (\x acc -> x+1) 0 如果参数列表是。 [1,2] ,基于 , 使用函数的一些内部知识 foo (与 海螺 使用其参数列表的内部知识(通过模式匹配)。但只要使用基本的组合符,比如 轻弹 (.) 等等,不是。