首页 > 解决方案 > 应用函子方面的一元序列

问题描述

假设我们有一个单子序列:

doSomething = do 
    a <- f 
    b <- g 
    c <- h 
    pure (a, b, c) 

我们可以使用 applicative functor 轻松地重写它:

doSomething2 = (,,) <$> f <*> g <*> h

但是如果单子序列看起来像这样:

doSomething' n = do 
    a <- f n 
    b <- g a 
    c <- h b 
    pure (a, b, c)

那里仍然可以使用应用程序吗?如果没有,障碍是什么?(另外在一本书中写到,尽管如此,我们可以将 applicative 和join一起使用,但我不知道如何使用)。

标签: haskell

解决方案


不,这正是 Monad 相比 Applicative 带来的额外力量。可以将类型的单子或应用值f a视为两部分:“效果”(发生在f数据结构中的东西)和“值”(发生在 type 的值中的东西a)。使用 Applicative,效果不可能依赖于值,因为 Applicative 中的函数无法将函数的结果(值)编织回效果中。Monad 中的(>>=)函数为您提供了这种能力;join同等强大。

关键是 for 的签名(>>=)包含一个看起来像这样的函数(a -> m b):你可以查看一个纯( ),然后根据它a选择一个效果。(m b)比较

(>>=) :: Monad m => (a -> m b) -> m a -> m b

fmap :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b

最后两个只接受完全在价值领域运作的功能:(a -> b),因此不能根据价值确定结构/效果。

当然,你仍然可以对这个do符号进行去糖,但是你必须在结果中使用一元操作:

doSomething'' n =
  f n >>= (\a -> 
    g a >>= (\b -> 
      h b >>= (\c -> 
        pure (a, b, c))))

推荐阅读