haskell - 如何解释函数实例的bind/>>=?

标签 haskell functional-programming monads applicative

我正在努力提高对 Applicative 的理解s 和 Monad s 通过在 Javascript 中实现它们的函数实例。我对 Haskell 的了解有限,我希望我的问题完全有道理。

这是我对 fmap 的实现, <*>>>=对于Functor , ApplicativeMonad Javascript中的类型类:

const fmap = f => g => x => f(g(x)); // B combinator
const apply = f => g => x => f(x) (g(x)); // S combinator
const bind = f => g => x => g(f(x)) (x); // ?

我不确定 bind是 Haskell 实现的正确翻译:
(>>=)  :: (r -> a) -> (a -> (r -> b)) -> r -> b

instance Monad ((->) r) where
f >>= k = \ r -> k (f r) r

前提是bind是正确的,它是如何解释的?我知道 Applicative可以对有效的计算进行排序。我也知道Monad此外,您还可以根据前一个效果的结果确定下一个效果。

我可以看到序列(Javascript 中的急切评估顺序):
  • apply : f(x) ... g(x) ... lambda(result of g) ... lambda 的结果
  • bind : f(x) ... g(result of f) ... lambda(x) ... lambda 的结果

  • 但是,bind功能看起来很奇怪。为什么是 fg反过来嵌套?具体如何Monad此实现中反射(reflect)的行为(根据前一个效果确定下一个效果)?其实g(f(x)) (x)看起来像一个带有翻转参数的函数组合,其中 g是二元函数。

    当我申请 apply/bind使用一元和二元函数,它们产生相同的结果。这没有多大意义。

    最佳答案

    Lee's answer 的一些脚注:

    However, the bind function looks pretty weird. Why are f and g nested the other way around?



    因为bind是倒退的。比较 (>>=)及其翻转版(=<<) :
    (>>=) :: Monad m => m a -> (a -> m b) -> m b
    (=<<) :: Monad m => (a -> m b) -> m a -> m b
    

    或者,在您的具体示例中:
    (>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)
    (=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
    

    在实践中,我们倾向于使用 (>>=)多于 (=<<) (因为 (>>=) ,从语法上讲,它非常适合用于构建的管道单子(monad)),从理论的角度来看 (=<<)是最自然的写法。特别是与 fmap 的异同。/(<$>)(<*>)更明显:
    (<$>) :: Functor f     =>   (a -> b) -> f a -> f b
    (<*>) :: Applicative f => f (a -> b) -> f a -> f b
    (=<<) :: Monad f       => (a -> f b) -> f a -> f b
    

    When I apply apply/bind with an unary and a binary function, they yield the same result. This doesn't make much sense.



    这是关于函数实例的一个偶然事实。让我们并排放置专门的签名:
    (<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
    (=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
    
    Monad超越Applicative通过提供根据先前结果确定下一个效果的方法(与“以前的效果”相反——Applicative 已经可以做到这一点)。在这种情况下,效果由一个函数组成,该函数在给定 r 类型的参数的情况下生成值。 .现在,由于可以翻转具有多个参数的函数(即返回函数的函数),因此 (r -> (a -> b)) 之间没有显着差异。和 (a -> (r -> b)) (flip 可以很容易地将一个更改为另一个),这使得 Monad (->) r 的实例完全等同于 Applicative一。

    关于haskell - 如何解释函数实例的bind/>>=?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40131562/

    相关文章:

    haskell - http-conduit 浏览器使用

    haskell - 使用 ST monad

    java.util.Function 或 Java 方法,哪一个是最佳实践?

    optimization - 延续+尾递归技巧是否真的用堆栈空间交换堆空间?

    scala - 在 for comprehension 中切换 monad

    haskell - 变形金刚下的转型

    haskell - 在 Haskell 中使用类似于事件日志的酸性状态

    haskell - 为什么函数式编程语言需要垃圾收集?

    javascript - 连接 Elm lang 和语义 UI

    haskell - 与 monad 中的值进行模式匹配