【问题标题】:Why sequence requires monad if applicative would suffice?如果 applicative 就足够了,为什么序列需要 monad?
【发布时间】: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 相关的函数(apsequence,...)保留即使引入了应用程序,它们的类型也是如此。此类更改不向后兼容,这是真的,但其他概括也不向后兼容 - 所以我不确定历史原因。 (Haskell 发生了很大变化:例如,过去 Monad 甚至不是 Functor 的子类)
  • @chi 如果[]foldr 被泛化为(a -> b -> b) -> b -> t a -> b 时被赋予Foldable 实例,这并不是一个不兼容的更改,是吗?当Applicative 被引入时,monads 并没有立即成为应用程序。现在Applicative Monad 的超类,sequence 可能会被重新输入。 (也就是说,我缺少什么角落案例?)
  • @chepner 不幸的是,在一般情况下,它仍然不兼容。例如,如果class C a where foo :: ainstance C [a] where foo = [],则length foo 编译如果length 强制[a],但如果length 只需要可折叠代码是不明确的。 (在 GHCi 中它之所以有效,只是因为 ExtendedDefaultRules)这是一个人为的例子,但在实际代码中可能会出现类似的歧义。

标签: haskell functional-programming


【解决方案1】:

Haskell 中有许多相同但不同的函数,因为 Applicative(分别是 Functor)过去不是 Monad 的超类。例如:

  • returnpure

  • ap<*>

  • liftM vs.liftA vs.fmap

  • liftM2liftM3 等。与liftA2liftA3 等相比。

  • mapM/forMtraverse/for

  • mapM_/forM_traverse_/for_

  • sequencesequenceA

  • mzero & mplus(来自MonadPlus)与empty & <|>(来自Alternative

带有原始Monad 签名的旧函数仍然存在,但在新代码中,由于实现了Applicative–Monad Proposal (AMP),您始终可以使用Applicative 版本,因为它们稍微更通用——也就是说,您始终可以将return 替换为pure,但反之则不行。

【讨论】:

  • 能否详细说明“兼容性原因”?具体来说,例如,如果今天将sequence 更改为具有sequenceA 的类型签名,会出现什么问题?
  • @JosephSible:你知道,我可能弄错了——没有什么应该仅仅因为更改签名而中断,而且实际上可能有计划在未来这样做。由于角色系统的问题,其他一些更改并未对 AMP 产生影响,例如将 join 移入 Monad 并删除 return, iirc。
猜你喜欢
  • 1970-01-01
  • 2020-02-03
  • 1970-01-01
  • 2016-04-22
  • 2018-03-23
  • 1970-01-01
  • 2013-06-28
  • 2020-05-19
  • 2011-03-08
相关资源
最近更新 更多