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