我们可以用 Alternative 做什么而不能用 Monoid 做什么?
What can we do with Alternative but cannot do with Monoid?
我读过 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 之间实际区别的代码示例吗?
问题不是 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
。 (我们也可以编写一个类型类来表达第一个更容易满足的约束。)
我读过 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 之间实际区别的代码示例吗?
问题不是 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
。 (我们也可以编写一个类型类来表达第一个更容易满足的约束。)