有什么是我们可以用 Alternative 做但用 Monoid 做不到的?

2024-01-08

I read 为什么是 MonadPlus 而不是 Monad + Monoid? https://stackoverflow.com/questions/23023961/why-monadplus-and-not-monad-monoid我理解理论上的差异,但我无法找出实际差异,因为对于 List 来说它看起来是一样的。

mappend [1] [2] == [1] <|> [2]

是的。也许有不同的实现

mappend (Just "a") (Just "b") /= (Just "a") <|> (Just "b")

但我们可以用与 Alternative 相同的方式实现 Maybe Monoid

instance Monoid (Maybe a) where
  Nothing `mappend` m = m
  m `mappend` _ = m

那么,有人可以展示代码示例来解释 Alternative 和 Monoid 之间的实际区别吗?

该问题不是重复的为什么是 MonadPlus 而不是 Monad + Monoid? https://stackoverflow.com/questions/23023961/why-monadplus-and-not-monad-monoid


这是一个非常简单的例子,说明了可以做的事情Alternative:

import Control.Applicative
import Data.Foldable

data Nested f a = Leaf a | Branch (Nested f (f a))

flatten :: (Foldable f, Alternative f) => Nested f a -> f a
flatten (Leaf x) = pure x
flatten (Branch b) = asum (flatten b)

现在让我们尝试同样的事情Monoid:

flattenMonoid :: (Foldable f, Applicative f) => Nested f a -> f a
flattenMonoid (Leaf x) = pure x
flattenMonoid (Branch b) = fold (flattenMonoid b)

当然,这不能编译,因为在fold (flattenMonoid b)我们需要知道扁平化会产生一个容器,其中的元素是Monoid。因此,让我们将其添加到上下文中:

flattenMonoid :: (Foldable f, Applicative f, Monoid (f a)) => Nested f a -> f a
flattenMonoid (Leaf x) = pure x
flattenMonoid (Branch b) = fold (flattenMonoid b)

啊,但是现在我们有一个问题,因为我们不能满足递归调用的上下文,它要求Monoid (f (f a))。因此,让我们将其添加到上下文中:

flattenMonoid :: (Foldable f, Applicative f, Monoid (f a), Monoid (f (f a))) => Nested f a -> f a
flattenMonoid (Leaf x) = pure x
flattenMonoid (Branch b) = fold (flattenMonoid b)

好吧,这只会让问题变得更糟,因为现在递归调用需要更多的东西,即Monoid (f (f (f a)))...

如果我们能写就太好了

flattenMonoid :: ((forall a. Monoid a => Monoid (f a)), Foldable f, Applicative f, Monoid (f a)) => Nested f a -> f a

甚至只是

flattenMonoid :: ((forall a. Monoid (f a)), Foldable f, Applicative f) => Nested f a -> f a

我们可以:而不是写forall a. Monoid (f a), 我们写Alternative f。 (我们也可以编写一个类型类来表达第一个更容易满足的约束。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有什么是我们可以用 Alternative 做但用 Monoid 做不到的? 的相关文章

随机推荐