(...) Typeclassopedia の記事によると、Monad にする前に、特定の型を Applicative にする必要があります (または、理論上はそうする必要があります)。
はい、括弧はさておき、まさにここでの問題です。理論的には、 anyも であるMonad 必要がApplicativeありますが、歴史的な理由から (つまり、Monadがより長く使用されているため)、実際には必須ではありません。の特徴はこれだけではありませんMonad。
baseHackageのパッケージのソースから取得した、関連する型クラスの実際の定義を検討してください。
ここにありApplicativeます:
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
...次のことが観察できます。
- 現在存在する型クラスを考えると、コンテキストは正しいです。つまり、 が必要
Functorです。
- これは、タプルを持ち上げるという (おそらく数学的な観点からはより自然な) 用語ではなく、関数の適用に関して定義されています。
- これには、定数関数を持ち上げるのと同等の技術的に余分な演算子が含まれています。
一方、ここにありますMonad:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
...次のことが観察できます。
- コンテキストは を無視するだけ
Applicativeでなく、 も無視しますFunctor。どちらも によって論理的に暗示されていますMonadが、明示的には必須ではありません。
returnと を使用したより数学的に自然な定義ではなく、関数の適用に関しても定義されますjoin。
- これには、定数関数を持ち上げるのと同等の技術的に余分な演算子が含まれています。
failまったく当てはまらないものも含まれます。
一般に、Monad型クラスがその基礎となる数学的概念と異なる点は、プログラミングの抽象化としての歴史をさかのぼることができます。いくつかは、それが共有する関数適用バイアスのようApplicativeに、関数型言語に存在することを反映しています。適切なクラスのコンテキストのようなfail、または欠如などの他のものは、何よりも歴史的な事故です。
つまり、 のインスタンスを持つことは のインスタンスをMonad意味し、さらに のインスタンスを意味するというApplicativeことですFunctor。クラス コンテキストは、これを明示的に形式化するだけです。それは関係なく真実のままです。Monad現状では、インスタンスが与えられると、完全に一般的な方法で と の両方FunctorをApplicative定義できます。は、より一般的であるというまったく同じ意味Applicativeよりも「強力ではありません」 。MonadMonadApplicativeApplicativeMonad
クラス コンテキストは、Functor f => Applicative f次の 2 つのことを言います。後者は前者を意味すること、およびその意味を満たすために定義が存在しなければならないことです。多くの場合、後者を定義すると暗黙のうちに前者が定義されますが、コンパイラは一般にそれを推測できないため、両方のインスタンスを明示的に書き出す必要があります。Eqandで同じことが観察できますOrd-- 後者は明らかに前者を意味しますが、 のインスタンスを定義するには、Eqインスタンスを定義する必要がありますOrd。