我试图借助https://namc.in/2018-02-05-foldables-traversals来了解Traversable。
作者在某处提到了以下句子:
Traversable对应用上下文而言是Foldable对Monoid 价值观。
他试图澄清什么?
我没有在Foldable to Monoid
之间建立联系。
请提供示例。
答案 0 :(得分:8)
开始时有foldr
:
foldr :: (a -> b -> b) -> b -> [a] -> b
有mapM
:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
通过让每种类型定义foldr
自己的定义来描述如何将其减少为单个值,将 [a]
推广到foldr
以外的数据类型。
-- old foldr :: (a -> b -> b) -> b -> [] a -> b
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
如果有一个monoid,则不必指定一个二进制函数,因为Monoid
实例已经提供了自己的起始值,并且知道如何组合两个值,这在其默认定义中显而易见。 foldr
的条款:
-- If m is a monoid, it provides its own function of type b -> b.
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
foldMap f = foldr (mappend . f) mempty
Traverse
进行从列表到可遍历类型的相同类型的概括,但对于mapM
:
-- old mapM :: Monad m => (a -> m b) -> [] a -> m ([] b)
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
(第一次定义mapM
时,没有Applicative
类;如果有,则可以定义mapA :: Applicative f => (a -> f b) -> [a] -> f [b]
; Monad
约束比是必要的。)
Applicative
本质上是单调的,因此Traverse
中不需要foldr
/ foldMap
得出的区分类型。
答案 1 :(得分:0)
本文(和the corresponding passage of the Wikibook)讨论的是如何将应用值的效果(或使用此处看到的语言,上下文)进行单调组合。与Foldable
的联系在于,类似列表的折叠最终最终等于将值进行单值组合(请参见chepner's answer,以及Foldr/Foldl for free when Tree is implementing Foldable foldmap?。至于应用上下文部分,有几种方法可以看一下这一点,其中之一是,对于任何Applicative f
和Monoid m
,f m
是一个等边线,pure mempty
为mempty
,{{1 }}作为liftA2 mappend
(this Ap
type from the reducers package的见证)。举一个具体的例子,让我们选择mappend
和f ~ Maybe
,这为我们提供了四种可能的组合:
m ~ ()
现在与All
(liftA2 mappend (Just ()) (Just ()) = Just ()
liftA2 mappend (Just ()) Nothing = Nothing
liftA2 mappend Nothing (Just ()) = Nothing
liftA2 mappend Nothing Nothing = Nothing
为Bool
的{{1}} id半体形成对比:
(&&)
它们完全匹配:mappend
代表mappend (All True) (All True) = All True
mappend (All True) (All False) = All False
mappend (All False) (All True) = All False
mappend (All False) (All False) = All False
,Just ()
代表True
,Nothing
代表False
。
现在让我们再看一下Wikibook示例:
liftA2 mappend
(&&)
通过将deleteIfNegative :: (Num a, Ord a) => a -> Maybe a
deleteIfNegative x = if x < 0 then Nothing else Just x
rejectWithNegatives :: (Num a, Ord a, Traversable t) => t a -> Maybe (t a)
rejectWithNegatives = traverse deleteIfNegative
应用于列表中的值而生成的GHCi> rejectWithNegatives [2,4,8]
Just [2,4,8]
GHCi> rejectWithNegatives [2,-4,8]
Nothing
值按照上面显示的方式进行单项合并,因此除非得到 all ,否则我们将获得Maybe
deleteIfNegative
的值为Nothing
。
这个问题也可以朝相反的方向解决。通过Maybe
的{{1}}实例...
Just
...我们可以从任何Applicative
中得到一个Const
,这样-- I have suppressed a few implementation details from the instance used by GHC.
instance Monoid m => Applicative (Const m) where
pure _ = Const mempty
Const x <*> Const y = Const (x `mappend` y)
就会单边组合单边值。这样就可以define foldMap
and friends in terms of traverse
。
最后一点,Applicative
作为类单曲面函子的类的理论描述涉及的内容与我在此介绍的内容截然不同。有关此问题和其他精美印刷品的进一步讨论,请参见Monoidal Functor is Applicative but where is the Monoid typeclass in the definition of Applicative?(如果您想更深入地研究,这里的所有答案都是值得的。)