这篇文章(和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 和liftA2 mappend 作为mappend(this Ap type from the reducers package 见证)。举个具体的例子,让我们选择f ~ Maybe 和m ~ ()。这给我们留下了四种可能的组合:
liftA2 mappend (Just ()) (Just ()) = Just ()
liftA2 mappend (Just ()) Nothing = Nothing
liftA2 mappend Nothing (Just ()) = Nothing
liftA2 mappend Nothing Nothing = Nothing
现在对比All,Bool 半群,(&&) 为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,liftA2 mappend 代表(&&)。
现在让我们再看一下 Wikibook 示例:
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
通过将deleteIfNegative 应用于列表中的值生成的Maybe 值按上述方式进行单曲面组合,因此我们得到Nothing,除非所有 Maybe值为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)
...我们可以从任何Monoid 中得到一个Applicative,这样(<*>) 将单曲面值组合在一起。这使得define foldMap and friends in terms of traverse成为可能。
最后一点,Applicative 作为单曲面函子类的范畴理论描述与我在此讨论的内容完全不同。有关此问题和其他细则的进一步讨论,请参阅Monoidal Functor is Applicative but where is the Monoid typeclass in the definition of Applicative?(如果您想深入了解,阅读那里的所有答案非常值得)。