申し訳ありませんが、私は自分の数学を本当に知らないので、Applicative型クラスの関数の発音方法に興味があります
あなたの数学を知っているかどうかは、ここではほとんど関係がないと思います。おそらくご存じのとおり、Haskellは、抽象的な数学のさまざまな分野、特にカテゴリ理論からいくつかの用語を借りており、そこからファンクタとモナドを取得しています。Haskellでのこれらの用語の使用は、正式な数学的定義とは多少異なりますが、通常、いずれにしても、それらは十分に説明的な用語になるほど十分に近いものです。
Applicative
型クラスは、間のどこかに座っているFunctor
とMonad
1が、それは同様の数学的基礎を持っていることを期待するので、。Control.Applicative
モジュールのドキュメントは次で始まります:
このモジュールは、ファンクターとモナドの中間の構造を記述します。純粋な式とシーケンスを提供しますが、バインディングは提供しません。(技術的には、強力で緩やかなモノイド関数です。)
うーん。
class (Functor f) => StrongLaxMonoidalFunctor f where
. . .
ほどキャッチーMonad
ではないと思います。
基本的にこれがまとめると、数学的にApplicative
特に興味深い概念に対応していないため、Haskellでの使用方法を表す既成の用語はありません。だから、今のところ数学を脇に置いてください。
何を呼び出すかを知りたい場合(<*>)
、それが基本的に何を意味するかを知るのに役立つかもしれません。
Applicative
とにかく、何が起こっているのですか、なぜそれをそれと呼ぶのですか?
どのようなApplicative
実際にになることは持ち上げるための方法である任意に機能をFunctor
。Maybe
(おそらく最も単純な非自明なFunctor
)とBool
(同様に最も単純な非自明なデータ型)の組み合わせを検討してください。
maybeNot :: Maybe Bool -> Maybe Bool
maybeNot = fmap not
この関数はfmap
、私たちが持ち上げることができますnot
に取り組んでからBool
、作業へMaybe Bool
。しかし、持ち上げたい場合はどう(&&)
でしょうか?
maybeAnd' :: Maybe Bool -> Maybe (Bool -> Bool)
maybeAnd' = fmap (&&)
まあ、それは我々が望むものではありませんすべてで!実際、それはほとんど役に立ちません。私たちは賢くなり、背中から別の人Bool
に忍び込むことができMaybe
ます...
maybeAnd'' :: Maybe Bool -> Bool -> Maybe Bool
maybeAnd'' x y = fmap ($ y) (fmap (&&) x)
...しかし、それは良くありません。一つには、それは間違っています。もう1つ、醜いです。引き続き試すことはできますが、複数の引数の関数を持ち上げて任意ので機能させる方法はないことがわかりましたFunctor
。迷惑!
一方、Maybe
のMonad
インスタンスを使用すると、簡単に実行できます。
maybeAnd :: Maybe Bool -> Maybe Bool -> Maybe Bool
maybeAnd x y = do x' <- x
y' <- y
return (x' && y')
さて、単純な関数を変換するだけで、それは多くの手間です。Control.Monad
これが、自動的に実行する関数を提供する理由liftM2
です。名前の2は、正確に2つの引数を持つ関数で機能することを示しています。同様の関数が3、4、および5の引数関数に存在します。これらの関数は優れていますが、完全ではなく、引数の数を指定することは醜く不器用です。
これにより、Applicative型クラスを紹介した論文が表示されます。その中で、著者は本質的に2つの観察をします:
- 複数の引数を持つ関数をに持ち上げる
Functor
ことは、非常に自然なことです
- そうすることは、の完全な機能を必要としません
Monad
通常の関数のアプリケーションは、用語の単純な並置によって記述されるため、「リフトアプリケーション」を可能な限りシンプルかつ自然にするために、このペーパーでは、アプリケーションに代わるインフィックス演算子をFunctor
紹介し、にリフトアップし、そのために必要なものを提供するタイプクラスを紹介します。。
これらすべてが次のポイントに私たちをもたらします:(<*>)
単に関数の適用を表します-それで、なぜあなたが空白の「並置演算子」をするのと違うようにそれを発音するのですか?
しかし、それがあまり満足できない場合は、Control.Monad
モジュールがモナドに対して同じことを行う関数も提供していることがわかります。
ap :: (Monad m) => m (a -> b) -> m a -> m b
ここでap
、当然のことながら、「適用」の略です。いずれか以来Monad
することができApplicative
、そしてap
後者に存在する機能のサブセットのみを必要とする、我々は、おそらくと言うことができるならば(<*>)
、オペレータはなかった、それが呼ばれるべきap
。
他の方向からもアプローチできます。Functor
昇降操作が呼び出されfmap
、それはの一般化だからmap
リストの操作。リストではどのような関数が機能します(<*>)
か?ap
もちろん、リストには何がありますが、それだけでは特に役に立ちません。
実際、リストにはおそらくもっと自然な解釈があります。次の型シグネチャを見ると、何が思い浮かびますか?
listApply :: [a -> b] -> [a] -> [b]
リストを並列に並べ、最初の各関数を2番目の対応する要素に適用するというアイデアには、とても魅力的なものがあります。古くからの友人にとって残念なことにMonad
、この単純な操作は、リストの長さが異なる場合、モナドの法則に違反します。しかし、それは問題Applicative
ありません。その場合、の汎用バージョンをつなぎ合わせる(<*>)
方法になるので、おそらくそれを呼び出すことを想像できますか?zipWith
fzipWith
このジッパーのアイデアは、実際に私たちを一周します。モノイド関数については、以前の数学のことを思い出してください。名前が示すように、これらはモノイドとファンクタの構造を組み合わせる方法です。どちらもおなじみのHaskell型クラスです。
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Monoid a where
mempty :: a
mappend :: a -> a -> a
これらを一緒に箱に入れて少し振ると、どのように見えますか?Functor
我々はのアイデアおこう、その型パラメータの構造から独立して、からMonoid
私たちは機能の全体的な形をしておこう:
class (Functor f) => MonoidalFunctor f where
mfEmpty :: f ?
mfAppend :: f ? -> f ? -> f ?
真に「空」を作成する方法があると想定したくはありませんFunctor
。また、任意の型の値を呼び出すことができないため、mfEmpty
as の型を修正しますf ()
。
またmfAppend
、一貫性のある型パラメーターを強制的に必要としないため、次のようになります。
class (Functor f) => MonoidalFunctor f where
mfEmpty :: f ()
mfAppend :: f a -> f b -> f ?
の結果タイプはmfAppend
何ですか?何も知らない任意のタイプが2つあるため、多くのオプションはありません。最も賢明なことは、両方を保持することです。
class (Functor f) => MonoidalFunctor f where
mfEmpty :: f ()
mfAppend :: f a -> f b -> f (a, b)
その時点mfAppend
で明らかzip
にリストの一般化されたバージョンになり、Applicative
簡単に再構築できます。
mfPure x = fmap (\() -> x) mfEmpty
mfApply f x = fmap (\(f, x) -> f x) (mfAppend f x)
これpure
は、のID要素に関連していることも示しているMonoid
ため、他の適切な名前は、ユニット値、null演算などを示唆するものである可能性があります。
それは長いので、要約すると:
(<*>)
は単に変更された関数アプリケーションなので、「ap」または「apply」として読み取るか、通常の関数アプリケーションとまったく同じ方法で省略できます。
(<*>)
またzipWith
、リストをおおまかに一般化しているため、「zip functors with」と読むことができますfmap
。「map a functor with」と読むのと同じです。
1つ目はApplicative
、名前が示すように、型クラスの意図に近いため、これをお勧めします。
実際、私はすべての解除されたアプリケーションオペレーターの寛大な使用と非発音を奨励します。
(<$>)
、これは単一引数関数を Functor
(<*>)
、複数の引数を持つ関数を Applicative
(=<<)
、を入力する関数をMonad
既存の計算にバインドします
3つすべては、基本的に、通常の関数アプリケーションであり、少しスパイスが効いています。