9

Monad + Monoid ではなく、なぜ MonadPlus なのかを読みました。理論的な違いは理解できますが、リストの場合は同じに見えるため、実際の違いを理解することはできません。

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

では、オルタナティブとモノイドの実際的な違いを説明するコード例を誰かが示すことができますか?

質問は、なぜ MonadPlus ではなく Monad + Monoidの複製ではありませんか?

4

1 に答える 1

15

でできることの非常に簡単な例を次に示します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ます。(最初の、より簡単に満たすことができる制約を表す型クラスを書くこともできます。)

于 2015-08-02T19:57:21.610 に答える