web-dev-qa-db-ja.com

型クラスMonadPlus、Alternative、Monoidの違いは?

標準ライブラリのHaskell型クラスMonadPlusAlternative、およびMonoidはそれぞれ、本質的に同じセマンティクスを持つ2つのメソッドを提供します。

  • 空の値:mzeroempty、またはmempty
  • 演算子a -> a -> a型クラスの値を結合します:mplus<|>、またはmappend

3つすべてが、インスタンスが準拠する必要がある次の法律を指定します。

mempty `mappend` x = x
x `mappend` mempty = x

したがって、3つの型クラスはすべて同じメソッドを提供しているようです。

Alternativesomemanyも提供しますが、通常はデフォルトの定義で十分なので、この質問に関してはそれほど重要ではありません。)

だから、私の質問は:なぜこれらの3つの非常に類似したクラスがあるのですか?スーパークラスの制約が異なる以外に、それらの間に実際の違いはありますか?

82
00dani

MonadPlusMonoidは異なる目的を果たします。

Monoidは、種類*の型でパラメーター化されます。

class Monoid m where
    mempty :: m
    mappend :: m -> m -> m

したがって、結合法則であり、単位を持つ明らかな演算子が存在するほとんどすべてのタイプに対してインスタンス化できます。

ただし、MonadPlusは、モノイド構造であることを指定するだけでなく、その構造がMonadの動作に関連していること、およびその構造は含まれている値を気にしないモナドでは、これは(一部)MonadPlusが種類* -> *の引数をとるという事実によって示されます。

class Monad m => MonadPlus m where
    mzero :: m a
    mplus :: m a -> m a -> m a

モノイドの法則に加えて、MonadPlusに適用できる2つの潜在的な法則のセットがあります。悲しいことに、コミュニティは彼らがどうあるべきかについて意見が分かれています。

少なくとも私たちは知っています

mzero >>= k = mzero

しかし、他の2つの競合する拡張、左(シック)分配法があります。

mplus a b >>= k = mplus (a >>= k) (b >>= k)

と左キャッチ法

mplus (return a) b = return a

したがって、MonadPlusのインスタンスは、これらの追加の法則の1つまたは両方を満たす必要があります。

では、Alternativeはどうですか?

ApplicativeMonadの後に定義され、論理的にはMonadのスーパークラスとして属しますが、主にHaskell 98に戻った設計者へのさまざまなプレッシャーのため、FunctorでさえMonadApplicativeのスーパークラスではありませんでした。 GHCのMonadの(まだ言語標準になっていない場合)。

事実上、AlternativeApplicativeに対して、MonadPlusMonadに対してです。

これらのために私達は得るだろう

empty <*> m = empty

MonadPlusの場合と同様に、同様の分配プロパティとcatchプロパティが存在し、少なくとも1つは満たす必要があります。

残念ながら、empty <*> m = empty法でさえ強すぎる主張です。 Backwards は保持されません。

MonadPlusを見ると、空の>> = f =空の法則がほぼ強制されています。空の構造には、とにかく関数fを呼び出すための「a」を含めることはできません。

ただし、ApplicativenotMonadのスーパークラスであり、AlternativenotMonadPlusのスーパークラスであるため、両方のインスタンスを別々に定義することになります。 。

さらに、ApplicativeMonadのスーパークラスであったとしても、私たちが従ったとしても、とにかくMonadPlusクラスが必要になるでしょう。

empty <*> m = empty

それはそれを証明するのに厳密には十分ではありません

empty >>= f = empty

したがって、何かがMonadPlusであると主張することは、それがAlternativeであると主張することよりも強力です。

現在、慣例により、特定の型のMonadPlusAlternativeは一致する必要がありますが、Monoid完全に異なる場合があります。

たとえば、MonadPlusAlternativeMaybeは、明らかなことを行います。

instance MonadPlus Maybe where
    mzero = Nothing
    mplus (Just a) _  = Just a
    mplus _        mb = mb

しかし、Monoidインスタンスは、セミグループをMonoidに持ち上げます。悲しいことに、Haskell 98には当時Semigroupクラスが存在しなかったため、Monoidを要求することによって存在しますが、そのユニットは使用しません。 ಠ_ಠ

instance Monoid a => Monoid (Maybe a) where
    mempty = Nothing
    mappend (Just a) (Just b) = Just (mappend a b)
    mappend Nothing x = x
    mappend x Nothing = x
    mappend Nothing Nothing = Nothing

TL; DRMonadPlusAlternativeよりも強力なクレームであり、これはMonoidよりも強力なクレームですが、型のMonadPlusおよびAlternativeインスタンスは関連している場合、Monoidは完全に異なるものになる場合があります(場合によってはまったく異なります)。

109
Edward KMETT