如何在Haskell中使用(=<<)来编写(< *>)

时间:2017-07-03 12:22:45

标签: haskell monads

有人可以解释为什么以下(<*>)(=<<)的表示有效:

f <*> a = (\f' -> return . f' =<< a) =<< f

2 个答案:

答案 0 :(得分:8)

这让我觉得这是一种刻意迟钝的写作方式。无论谁给你这个代码都试图搞砸你。以下是ap的通常定义,它清晰易懂:

ap f a = do
    f' <- f
    a' <- a
    return (f' a')

我们可以通过常规do desugaring转换运行此操作,将<-替换为>>=

ap f a =
    f >>= \f' ->
    a >>= \a' ->
    return (f' a')

现在,请注意最里面的术语是\a' -> return (f' a'),可以写成return . f'

ap f a =
    f >>= \f' ->
    a >>= return . f'

然后,从(=<<) = flip (>>=)开始,我们可以通过交换参数将>>=替换为=<<

ap f a = f >>= (\f' -> return . f' =<< a)  -- reverse inner bind
ap f a = (\f' -> return . f' =<< a) =<< f  -- reverse the other bind

你去。

答案 1 :(得分:2)

名称fa的使用极其令人困惑,因为名字具有暗示性(&#34; f&#34;唤起&#34;功能&#34;,但不是&#39; T)。引用名称也可能令人困惑。当您仍在学习并且不确定默认运算符优先级时,不应省略Parens。 do的可选花括号和分号也是如此。

这两个名称应该是fsas。改变它们可能是预期答案的一部分。你有

fs <*> as = (\f -> (return . f) =<< as) =<< fs
          = fs >>= (\f ->
            as >>= (return . f))                -- by definition of >>= and =<<
          = fs >>= (\f ->
            as >>= (\a -> (return . f) a))      -- by "eta expansion"
          = fs >>= (\f ->
            as >>= (\a -> return (f a)))        -- by `(.)` reduction
          = do { f <- fs 
               ; a <- as 
               ; return (f a) }                 -- by `do` syntax definition

因为这是do语法的定义方式。那个the definition的{/ em> ap,其中<*>应该是替身。

不言而喻,这只适用于不仅仅是一个应用程序,而且也适用于Monad的类型。

使用 monad comprehensions ,最后一个是

          = [f a | f <- fs, a <- as]

本身很清楚。