web-dev-qa-db-ja.com

ファンクターとモナドの違いは何ですか?

ここにも同様の質問がありますが、それらは特定のプログラミング言語に関連付けられており、概念レベルでの回答を探しています。

私が理解しているように、ファンクターは本質的に不変のコンテナーであり、別のファンクターを派生させるmap() APIを公開します。特定のファンクターをモナドと呼ぶことを可能にする追加はどれですか?

私が理解しているように、すべてのモナドはファンクターですが、すべてのファンクターがモナドであるとは限りません。

15

(これは圏論の概念の簡単な説明になることに注意してください)

ファンクタ

ファンクターは、値のセットaから別の値のセットへの関数です:_a -> b_。プログラミング言語の場合、これは_String -> Integer_から始まる関数である可能性があります。

function fn(text: string) : integer

組成

合成とは、ある関数の値を次の関数の値への入力として使用する場合です:fa(fb(x))。例えば:

hash(lowercase(text))

モナド

モナドを使用すると、他の方法では構成できないファンクターを作成するか、コンポジションに機能を追加してファンクターを作成するか、またはその両方を行うことができます。

  • 最初の例は、ファンクターのモナドString -> (String, Integer)です。

  • 2番目の例は、値に対して呼び出された関数の数をカウントするモナドです。

モナドには、必要な機能に加えて他の2つの機能を担当するFunctor Tが含まれています。

  • input -> T(input)
  • T(T(input)) -> T(input)

最初の関数を使用すると、入力値をモナドが作成できる値のセットに変換できます。 2番目の機能は構成を可能にします。

したがって、結論として、すべてのモナドはファンクターではありませんが、ファンクターを使用してその目的を完了します。

圏論に入らずに私の理解を説明させてください、

ファンクターとモナドはどちらも、ラップされた出力を返すラップされた入力にtoolを提供します。

ファンクター=ユニット+マップ(ツール)

ここで、unit =生の入力を受け取り、それを小さなコンテキスト内にラップするものです。

map =関数を入力として受け取り、それをラッパーの生の値に適用して、ラップされた結果を返すツールです。

例:整数を2倍にする関数を定義しましょう// doubleMe :: Int a-> Int b const doubleMe = a => 2 * a; Maybe(2).map(doubleMe)// Maybe(4)

モナド=ユニット+フラットマップ(またはバインドまたはチェーン)

flatMap =名前がこぼれたときにマップを平坦化するツールです。以下の例ですぐに明らかになります。

例:両方が空白でない場合にのみ2つの文字列を追加するカリー化関数があるとします。

以下のように定義させてください。
append::( string a、string b)->たぶん(string c)

Map(ツールはFunctorに付属)の問題を見てみましょう。

Maybe( "a")。map(append( "b"))// Maybe(Maybe( "ab"))

どうしてここに2つあるの?

まあ、それはマップが行うことです、それはラップされた値に提供された関数を適用し、結果をラップします。

これをいくつかのステップに分けてみましょう。

ステップ1:マップされた関数をラップされた値に適用するここで、マップされた関数はappend( "b")であり、ラップされた値は "a"であり、結果はMaybe( "ab")

step2:Maybe(Maybe( "ab"))を返す結果をラップします。

これで、関心のある値が2回ラップされます。救助するflatMapがここにあります。
Maybe( "a")。flatMap(append( "b"))// Maybe( "ab")

もちろん、ファンクターとモナドは他のいくつかの法律にも従わなければなりませんが、これは求められている範囲内ではないと思います。

1