Traversable 概念的术语

Terminology of the Traversable concept

为什么我们将结构翻转称为 "sequence",为什么我们谈论 "traverse" 和 "Traversal"?

我将这些概念的实现添加到 haskell 中以供讨论...

class (Functor t, Foldable t) => Traversable t where
    {-# MINIMAL traverse | sequenceA #-}

    -- | 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

它是“序列”,而不是"a"。 IE。 "Arrange in a particular order", here from left to right. And it is a generalization of sequence :: Monad m => [m a] -> m [a](注意旧的 base 版本),这可能会使名称更明显。

让我们首先考虑 fmap:

fmap :: Functor t => (a -> b) -> t a -> t b

我们可以将它的作用描述为在 t a 中找到所有 a 值并对它们应用一个函数。请注意,除了无限结构恶作剧之外,就最终结果而言,fmap 的实现达到 a 值以修改它们的顺序并不重要。

现在让我们来看看traverse:

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

fmap 一样,traverse 也涉及将函数应用于在结构中找到的值(难怪 traverse 的前身被称为 mapM)。然而,traverse 也会为每个 a 值(a -> f b 中的 f)产生应用效果,它涉及按某种顺序组合这些效果以获得整体效果f (t b) 结果。一般而言(即只要 f 不是可交换应用,例如 Maybe),效果的顺序会影响结果。既然如此,任何 Traversable 实例都对应于访问结构中的值的特定顺序。 "traverse" 这个名字(也就是 Will Ness 指出的 "travel across or through")就是为了传达这种方向感。

在相关说明中,traverse 可以分解为一个普通映射,该映射会产生效果,然后对这些效果进行排序...

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

traverse f = sequenceA . fmap f
sequenceA = traverse id

...因此 "sequence" 名称。

还值得强调的是,traverse 确实捕获了通过结构和在每一站做事的各种方式(参见 forflip traverse 的名称)。特别是,我们通过选择 Identity 作为 Applicative functor(即实际上不产生任何效果)来恢复 fmap,并且通过选择 Monoid m => Const m 代替。我们不能traverse做的事情包括删除、复制或重新排列元素——它不允许像一般的[=61]那样以任意方式拆除数据结构=] 确实如此。使用 traverse,我们可以移动 Traversable 结构,但不能对其进行重塑。