標準ライブラリのHaskell型クラスMonadPlus
、Alternative
、およびMonoid
はそれぞれ、本質的に同じセマンティクスを持つ2つのメソッドを提供します。
mzero
、empty
、またはmempty
。a -> a -> a
型クラスの値を結合します:mplus
、<|>
、またはmappend
。3つすべてが、インスタンスが準拠する必要がある次の法律を指定します。
mempty `mappend` x = x
x `mappend` mempty = x
したがって、3つの型クラスはすべて同じメソッドを提供しているようです。
(Alternative
はsome
とmany
も提供しますが、通常はデフォルトの定義で十分なので、この質問に関してはそれほど重要ではありません。)
だから、私の質問は:なぜこれらの3つの非常に類似したクラスがあるのですか?スーパークラスの制約が異なる以外に、それらの間に実際の違いはありますか?
MonadPlus
とMonoid
は異なる目的を果たします。
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
はどうですか?
Applicative
はMonad
の後に定義され、論理的にはMonad
のスーパークラスとして属しますが、主にHaskell 98に戻った設計者へのさまざまなプレッシャーのため、Functor
でさえMonad
はApplicative
のスーパークラスではありませんでした。 GHCのMonad
の(まだ言語標準になっていない場合)。
事実上、Alternative
はApplicative
に対して、MonadPlus
はMonad
に対してです。
これらのために私達は得るだろう
empty <*> m = empty
MonadPlus
の場合と同様に、同様の分配プロパティとcatchプロパティが存在し、少なくとも1つは満たす必要があります。
残念ながら、empty <*> m = empty
法でさえ強すぎる主張です。 Backwards は保持されません。
MonadPlusを見ると、空の>> = f =空の法則がほぼ強制されています。空の構造には、とにかく関数f
を呼び出すための「a」を含めることはできません。
ただし、Applicative
はnotMonad
のスーパークラスであり、Alternative
はnotMonadPlus
のスーパークラスであるため、両方のインスタンスを別々に定義することになります。 。
さらに、Applicative
がMonad
のスーパークラスであったとしても、私たちが従ったとしても、とにかくMonadPlus
クラスが必要になるでしょう。
empty <*> m = empty
それはそれを証明するのに厳密には十分ではありません
empty >>= f = empty
したがって、何かがMonadPlus
であると主張することは、それがAlternative
であると主張することよりも強力です。
現在、慣例により、特定の型のMonadPlus
とAlternative
は一致する必要がありますが、Monoid
は完全に異なる場合があります。
たとえば、MonadPlus
のAlternative
とMaybe
は、明らかなことを行います。
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; DRMonadPlus
はAlternative
よりも強力なクレームであり、これはMonoid
よりも強力なクレームですが、型のMonadPlus
およびAlternative
インスタンスは関連している場合、Monoid
は完全に異なるものになる場合があります(場合によってはまったく異なります)。