【发布时间】:2019-04-03 03:41:32
【问题描述】:
序列的签名是
sequence :: Monad m => t (m a) -> m (t a)
但我们可以将其实现为
sequence = traverse id
要求 m 只是 Applicative。如果 monad 是应用程序,那么为什么还要在类型级别上设置这个约束呢?
【问题讨论】:
-
历史原因。
sequenceA代表现代的哈斯凯利斯塔。 -
更具体地说:它是在
Applicative已知之前定义的,后来被保留是因为当Applicative被添加到base时,它还不是Monad的超类。跨度> -
由于某种原因,过去的几个函数在引入时已经泛化为可折叠/可遍历,但之前与 monad 相关的函数(
ap,sequence,...)保留即使引入了应用程序,它们的类型也是如此。此类更改不向后兼容,这是真的,但其他概括也不向后兼容 - 所以我不确定历史原因。 (Haskell 发生了很大变化:例如,过去Monad甚至不是Functor的子类) -
@chi 如果
[]在foldr被泛化为(a -> b -> b) -> b -> t a -> b时被赋予Foldable实例,这并不是一个不兼容的更改,是吗?当Applicative被引入时,monads 并没有立即成为应用程序。现在Applicative是Monad的超类,sequence可能会被重新输入。 (也就是说,我缺少什么角落案例?) -
@chepner 不幸的是,在一般情况下,它仍然不兼容。例如,如果
class C a where foo :: a与instance C [a] where foo = [],则length foo编译如果length强制[a],但如果length只需要可折叠代码是不明确的。 (在 GHCi 中它之所以有效,只是因为ExtendedDefaultRules)这是一个人为的例子,但在实际代码中可能会出现类似的歧义。
标签: haskell functional-programming