Functor、Applicative Functor和Monad之间的关系

35
当阅读类型类相关内容时,我发现函子、应用函子和单子之间的关系是严格递增的。函子是可以映射的类型。应用函子可以对某些影响进行相同的操作。单子可以对可能不受限制的影响进行相同的操作。此外:
Every Monad is an Applicative Functor
Every Applicative Functor is a Functor

应用函子的定义清楚地表明:

class Functor f => Applicative f where
  pure  :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

但是Monad的定义是:

class Monad m where
  return :: a -> m a
  (>>=)  :: m a -> (a -> m b) -> m b
  (>>)   :: m a -> m b -> m b
  m >> n = m >>= \_ -> n
  fail   :: String -> m a

根据 Brent Yorgey 的优秀 typeclassopedia,单子的另一种定义可能是:
class Applicative m => Monad' m where
  (>>=) :: m a -> (a -> m b) -> m b

显然更简单,而且会巩固Functor < Applicative Functor < Monad的定义。那么为什么不采用这个定义呢?我知道applicative functors是新的,但根据2010 Haskell Report第80页,这并没有改变。为什么呢?


1
单子与无限制效应相同。你是从哪里得到这个想法的? - Conal
1
我当然犯了一个错误,将单子和IO之间放置了一个等号。更正确的说法是什么? - Magnus Kronqvist
7
也许“dependent”是一个更好的词。Applicative和Monad的主要区别在于(<*>) :: f (a -> b) -> f a -> f b(=<<) :: (a -> m b) -> m a -> m b的类型,即结果中的m部分可以依赖于输入的a,而对于applicative,结果中的f部分必须独立于a输入的值相同。 - hammar
1
class Applicative m => Monad'' m where join :: m (m a) -> m a 是另一个可能的最小完整定义。(也在typeclassopedia中注明) - Dan Burton
7
@MagnusKronqvist:这里有一个我喜欢的Monad比Applicative更好的解释:Applicative强制计算结构是静态的,而Monad允许它是动态的,取决于其他计算的结果。 - ehird
显示剩余2条评论
2个回答

27
每个人都希望看到Applicative成为Monad的超类,但这会破坏很多代码(如果删除return,每个当前的Monad实例都会变得无效),因此每个人都希望暂缓,直到我们可以以避免破坏代码的方式扩展语言(在这里看看一个著名的提案)。
Haskell 2010是一种保守的、渐进的改进,通常只标准化了一些无争议的扩展,并在某些方面破坏兼容性,使标准符合所有现有的实现。事实上,Haskell 2010的库甚至不包括Applicative——标准库中的内容比你想象的要少。
希望我们很快能看到情况有所改善,但幸运的是,这通常只是一种轻微的不便(需要在通用代码中编写liftM而不是fmap等)。

1
并不是每个人都希望Applicative成为Monad的超类。 - Bertie Wheen

8

如果在这个时候改变Monad的定义,就会破坏很多现有代码(任何定义Monad实例的代码),这是不值得的。

只有当这样的改变带来实际上的巨大好处时,才有必要破坏向后兼容性。 在这种情况下,好处并不是那么大(而且大部分是理论上的),不能证明这样的改变足以使这么多代码失效。


1
你是指它会以何种方式破坏兼容性?'Applicative m => Monad m' 可能会破坏某些现有的代码。但修复应该很容易,而且 Haskell 2010 已经不完全向后兼容了。 - Magnus Kronqvist
Haskell 2010完全向后兼容实际的Haskell 98实现,我相信;语法上的破坏性变化是每个编译器已经按照Haskell 2010规定实现的。 - ehird
3
每个人都希望看到 Applicative 成为 Monad 的一个超类,但这样做会打破很多代码,因此每个人都希望等到我们可以以避免破坏代码的方式扩展语言后再考虑。请参见这里提出的一个著名建议。链接 - ehird
@ehird 谢谢,虽然它几乎是一个答案! - Magnus Kronqvist
@MagnusKronqvist:我忍不住把它扩展成了一个答案 :) - ehird

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接