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

How to write (<*>) using (=<<) in Haskell

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

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

我觉得这是一种刻意写成的迟钝方式。给你这个代码的人是想惹你生气。下面是 ap 的通常定义,简洁易懂:

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

我们可以 运行 通过通常的 do 脱糖转换,将 <- 替换为 >>=:

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

给你。

名称 fa 的使用非常令人困惑,因为名称具有暗示性("f" 让人想起 "function",但事实并非如此)。素数名称也可能令人困惑。当您仍在学习并且不确定默认运算符优先级时,不应省略括号。 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 of ap<*> 应该是它的替代品。

不言而喻,这仅适用于不仅是 Applicative,而且还是 Monad 的类型。

有了monad comprehensions,最后一个写成

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

这本身就很清楚了。