10

「Haskell を学ぼう!」著者は、インスタンスが次のように実装されていると主張していApplicative IOます。

instance Applicative IO where
    pure = return
    a <*> b = do
        f <- a
        x <- b
        return (f x)

私は間違っているかもしれませんが、 と の両方returndo固有の構造 (いくつかの砂糖漬けの bind (>>=)) は から来ているようMonad IOです。それが正しいと仮定すると、私の実際の質問は次のとおりです。

実装が関数/コンビネータApplicative IOに依存するのはなぜですか?Monad IO

Applicative よりも強力な概念ではありませんMonadか?


編集(いくつかの説明):

Typeclassopedia の記事によると、特定の型を作成するApplicative 前にその型である必要があるためMonad(または理論上はそうあるべきである)、この実装は私の直感に反しています。

4

5 に答える 5

12

(...) 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現状では、インスタンスが与えられると、完全に一般的な方法で と の両方FunctorApplicative定義できます。は、より一般的であるというまったく同じ意味Applicativeよりも「強力ではありません」 。MonadMonadApplicativeApplicativeMonad

クラス コンテキストは、Functor f => Applicative f次の 2 つのことを言います。後者は前者を意味すること、およびその意味を満たすために定義が存在しなければならないことです。多くの場合、後者を定義すると暗黙のうちに前者が定義されますが、コンパイラは一般にそれを推測できないため、両方のインスタンスを明示的に書き出す必要があります。Eqandで同じことが観察できますOrd-- 後者は明らかに前者を意味しますが、 のインスタンスを定義するには、Eqインスタンスを定義する必要がありますOrd

于 2011-07-03T23:15:29.287 に答える
9

タイプは Haskell では抽象的であるため、一般的なforIOを実装したい場合は、IO でサポートされている操作でそれを行う必要があります。良い選択と思われる操作の観点から実装できるので。それを実装する別の方法を考えることができますか?ApplicativeIOApplicativeMonad

はい、Applicativeある意味で よりも強力ではありませんMonad

于 2011-07-03T18:47:20.297 に答える
7

Applicative はMonad よりも強力な概念ではありませんか?

はい、したがって、 があるときはいつでもそれを にするMonadことができますApplicativeIO例の他のモナドに置き換えることができ、それは有効なApplicativeインスタンスになります。

たとえ ば、カラー プリンタはグレースケール プリンタよりも強力であると考えられているかもしれませんが、それでもカラー プリンタを使用してグレースケール イメージを印刷できます。

もちろん、and setに基づいてMonadインスタンスを作成することもできますが、一般的に定義することはできません。これが、より強力であるということです。Applicativereturn = pure>>=Monad

于 2011-07-03T19:36:09.407 に答える
3

完璧な世界では、すべてMonadApplicative(つまりclass Applicative a => Monad a where ...) になりますが、歴史的な理由から、両方の型クラスは独立しています。したがって、この定義は一種の「後方」(より強力な抽象化を使用して、より強力でない抽象化を実装する) であるというあなたの観察は正しいです。

于 2011-07-03T21:01:41.247 に答える
1

古いバージョンの GHC については完全に適切な回答が既にありますが、最新バージョンでは実際にあるclass Applicative m => Monad mため、質問には別の回答が必要です。

GHC の実装に関して: GHC は、特定の型に対してどのインスタンスが定義されているかをチェックしてから、それらのいずれかをコンパイルしようとします。

コードのセマンティクスに関してはclass Applicative m => Monad m、インスタンスを「最初に」定義する必要があるという意味ではありませんApplicative。プログラムの最後までにインスタンスが定義されていない場合、コンパイラは中止されます。

于 2015-10-28T05:02:10.653 に答える