Applicative,Foldable和Traversable之间有什么关系?

时间:2017-09-02 21:46:50

标签: haskell

我试图了解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

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

1 个答案:

答案 0 :(得分:3)

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

您提出的定义有点误导,因为正如您所指出的那样,它们是相互依赖的。当你真正实现其中一个时,你会遇到空集合问题。并且您会遇到<*>的需要,因为Functor无法为某些仿函数f a汇总f的不同值。

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

据说有些类型您不需要pure或不需要<*>。如果您的收藏品永远不会是空的,那么您就不需要pure,例如NonEmpty。如果您的收藏品从不包含多个元素,则您不需要<*>,例如Maybe。有时候你也不需要,只有fmap才可以逃脱,例如一个元组部分,例如(a,))。

Haskell可以有一个更细粒度的类型层次结构,将Applicative分解为更细粒度的部分,使用pure<*>的单独类,这样可以让你做出不同的约束较弱的Traversable版本(例如TraversableNonEmptyTraversableSingleton)。据推测,在Haskell中对此的需求还不够大。

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

关于你的第二个问题,如果你知道该怎么做就是拆掉某些东西,你仍然可以沿途执行效果,但你不一定能恢复原来的结构。因此sequenceA_Foldable的原因。它的强度绝对低于sequenceA