【问题标题】:What is the relationship between Applicative, Foldable and Traversable?Applicative、Foldable 和 Traversable 是什么关系?
【发布时间】:2017-09-02 21:46:49
【问题描述】:

我试图从Applicative 接口了解究竟需要什么才能执行任何traverse。我被卡住了,因为它们没有在默认实现中使用,就好像约束是严格的一样。 Haskell 的类型系统是否太弱,无法描述实际需求?

-- | Map each element of a structure to an action, evaluate these actions
-- from left to right, and collect the results. For a version that ignores
-- the results see 'Data.Foldable.traverse_'.
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

-- | Evaluate each action in the structure from left to right, and
-- and collect the results. For a version that ignores the results
-- see 'Data.Foldable.sequenceA_'.
sequenceA :: Applicative f => t (f a) -> f (t a)
sequenceA = traverse id

一个可能相关的附带问题,为什么在Foldable 中定义sequenceA_

【问题讨论】:

标签: haskell


【解决方案1】:

traversesequenceA 都需要处理Traversable 为空时发生的情况。然后,Applicative 上下文中将没有任何元素可用于将其他内容添加到其中,因此您将需要 pure

您提出的定义有点误导,因为正如您所指出的,它们是相互依赖的。当你去实际实现其中之一时,你会遇到空集合问题。你会遇到对<*> 的需求,因为Functor 没有为某些函子f 聚合不同的f a 值提供便利。

因此存在Applicative 约束,因为对于大多数类型,为了实现traversesequenceA,您需要Applicative 提供的工具。

话虽如此,有些类型您不需要pure 或不需要<*>。如果您的收藏永远不会为空,则不需要pure,例如NonEmpty。如果您的收藏从来没有超过一个元素,则不需要<*>,例如Maybe。有时你也不需要,你可以只用fmap,例如元组部分,例如 (a,))。

Haskell 可以有一个更细粒度的类型类层次结构,它将Applicative 分解为更细粒度的部分,为pure<*> 提供单独的类,然后允许您使用不同版本的Traversable较弱的约束。 Edward Kmett 的库semigroupoids 朝着这个方向发展,尽管它并不完美,因为它不能将实际的超类添加到base 类中。它有Apply,即Applicative,但没有pure,还有Traversable1,它是Traversable 的变体,它使用Apply 而不是Applicative,因此要求它的类型永远不能为空。

请注意,其他生态系统已选择具有更细粒度的类型类层次结构(请参阅 Scala 的 catsscalaz 库)。我个人觉得这种区别偶尔有用,但不是绝对有用。

至于你的第二个问题,如果你只知道如何拆除某物,你仍然可以在此过程中执行效果,但你不一定能恢复原始结构。因此为什么sequenceA_Foldable 中。它严格来说不如sequenceA 强大。

【讨论】:

  • "Haskell 可以有一个更细粒度的类型类层次结构,它将Applicative 分解为更细粒度的部分,为pure<*> 提供单独的类" -- PureScript 有这个,定义Apply (<*>) 和 Applicative (pure) 作为单独的类型类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
  • 2016-04-05
相关资源
最近更新 更多