为什么sequenceA需要Traversable?

时间:2015-12-08 00:50:16

标签: haskell

来自Typeclassopedia

sequence :: Monad m => [m a] -> m [a]
     

获取计算列表并将它们组合成一个计算,该计算收集其结果列表。序列具有Monad约束也是历史事故,因为它实际上只能以Applicative的形式实现。

事实上,sequenceAApplicative类型进行操作。

sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)

但是请等一下,为什么sequenceA在没有它的情况下可以实现Traversable约束?

seqA :: Applicative f => [f a] -> f [a]
seqA = foldr fx (pure [])
         where
           fx f fs = pure (:) <*> f <*> fs)

1 个答案:

答案 0 :(得分:7)

这是一个可能最初令人困惑的主题,因为它周围有很多历史和变化,而旧的解释已经过时了。历史大致如下:

  1. sequence操作的想法可以追溯到20世纪90年代,当时Monad类被纳入Haskell,人们首先为它制定了通用操作。您从Typeclassopedia引用的签名反映了这一点:sequence :: Monad m => [m a] -> m [a]。它可以与任何monad一起使用,但它在列表上工作是硬编码的。
  2. Applicative班是在2000年代中后期开发的;每个人都引用的开创性论文是McBride和Patterson(2008),"Applicative Programming with Effects"。麦克布莱德和帕特森也注意到:
    • 旧的monadic sequence操作实际上可以推广到dist :: Applicative f => [f a] -> f [a]Monad约束太窄了!
    • 同样,旧mapM功能(与sequence关闭)概括为traverse :: Applicative f => (a -> f b) -> [a] -> f [b]
    • 这可以通过将这些操作放入他们在论文中提出的Traversable类来推广到非列表数据结构。
  3. 已将ApplicativeTraversable类添加到GHC base库中,并进行了一些小的更改。 dist函数的名称为sequenceA,而Foldable类的加入Traversable仅适用于仅支持Traversable要求子集的类型。
  4. 这些课程非常受欢迎。但是,这表明原来的sequence :: Monad m => [m a] -> m [a]签名在后见之明错误
  5. 最后,快进到2015年,当GHC实施Applicative/Monad Proposal(使Applicative成为Monad的超类)和Foldable/Traversable Proposal时,基础库是修改后,以使他们接近理想,后见之明的设计。
  6. 然而,可折叠/可交叉提案未改变sequence的签名。我不能确切地告诉你为什么,但答案将是一些钝化的细节,归结为历史原因,向后兼容性或类似的东西。但我可以告诉你,如果我们可以重新开始:

    1. sequence会有sequenceA的签名;
    2. sequenceA不会独立于sequence;
    3. 而存在
    4. mapM只是traverse,签名错误,因此也不会独立存在。