1. ホーム
  2. haskell

[解決済み] MonadPlus, Alternative, Monoidの型別は?

2023-04-16 23:03:01

質問

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

  • 空の値。 mzero , empty または mempty .
  • 演算子 a -> a -> a は,型クラス内の値を結合する演算子である。 mplus , <|> または mappend .

3つとも、インスタンスが遵守すべきこれらの法則を規定しています。

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

このように,3つの型クラスはいずれも と同じ メソッドを提供しているようです。

( Alternative もまた somemany がありますが、通常はそれらのデフォルトの定義で十分なので、この質問の観点ではあまり重要ではありません)。

私の疑問は、なぜこれら 3 つの非常によく似たクラスがあるのか、ということです。スーパークラスの制約が異なる以外に、これらの間に何か本当の違いがあるのでしょうか?

どのように解決するのですか?

MonadPlus そして Monoid は異なる目的で使用されます。

A 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

モノイドの法則に加え、以下の2つの法則を適用することができます。 MonadPlus . 悲しいことに、コミュニティはそれらが何であるべきかについて意見が一致していません。

少なくとも、私たちは

mzero >>= k = mzero

という拡張がありますが、他に左(sic)分配法則という競合する拡張があります。

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

と左のキャッチフレーズ

mplus (return a) b = return a

というわけで、どのインスタンスも MonadPlus のインスタンスは、これらの追加的な法則の一つまたは両方を満たす必要があります。

では Alternative ?

Applicative の後に定義されました。 Monad の上位クラスとして定義され、論理的には Monad に属するものですが、Haskell 98 のころの設計者に対するさまざまな圧力のためか、この Functor のスーパークラスではありませんでした。 Monad のスーパークラスではありませんでした。今、私たちはついに Applicative のスーパークラスとして Monad のスーパークラスとしてGHCに追加されました(言語標準にはまだないようです)。

効果的に AlternativeApplicativeMonadPlus になります。 Monad .

この場合、次のようになります。

empty <*> m = empty

と同じように MonadPlus であり、同様の分配性と捕捉性が存在し、そのうちの少なくとも1つは満たす必要があります。

残念ながら、たとえ empty <*> m = empty の法則は強すぎる主張です。それは 後方 には当てはまりません。

MonadPlusを見ると、空 >>= f = 空の法則がほぼ強制されています。空の構成は、関数を呼び出すために、その中にいかなる'a'も持つことができません。 f を呼び出すことができません。

しかし Applicative ではなく のスーパークラスです。 MonadAlternative ではない のスーパークラスです。 MonadPlus のスーパークラスではないので、両方のインスタンスを別々に定義することになります。

さらに、たとえ Applicative がスーパークラスであったとしても Monad のスーパークラスであれば、結局は MonadPlus クラスに従ったとしても

empty <*> m = empty

ということを証明するには、厳密には十分ではありません。

empty >>= f = empty

つまり、何かを主張することは MonadPlus であると主張するよりも Alternative .

さて、慣例により MonadPlusAlternative は一致するはずですが Monoid 完全に は異なるかもしれません。

例えば MonadPlusAlternative に対して Maybe 当たり前のことを当たり前にやる。

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

が、その Monoid インスタンスは半グループを Monoid . 悲しいことに Semigroup クラスが存在しなかったため、Haskell 98 では、このクラスは 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;DR MonadPlus よりも強い主張です。 Alternative よりも強い主張であり、さらに Monoid であり、一方 MonadPlusAlternative のインスタンスは関連しているはずです。 Monoid は全く別のものである可能性があります(時にはそうである場合もあります)。