[解決済み] <*>は何と呼ばれ、何をするのですか?[クローズド]
質問
Applicative型クラスのこれらの関数はどのように動作するのでしょうか?
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
(つまり、演算子でなかったら、何と呼ばれているのでしょうか)
余談ですが、もしあなたが
pure
を数学者でない人にも親しみやすい名前に変更できるとしたら、あなたはそれを何と呼びますか?
どのように解決するのですか?
<ブロッククオート申し訳ありませんが、私は本当に数学を知らないので、私はApplicative型クラスの関数をどのように発音するのか気になります。
数学がわかるかどうかは、ここではほとんど関係ない、と私は思います。おそらくご存知のように、Haskell は抽象数学のさまざまな分野からいくつかの用語を拝借しており、特に カテゴリ理論 そこからファンクターとモナドを得ました。Haskell でのこれらの用語の使用は、正式な数学的定義から多少離れていますが、いずれにせよ、良い説明用語となるには十分なほど通常近いものです。
は
Applicative
型クラスの間に位置する
Functor
と
Monad
というように、同じような数学的根拠を持っていることが予想されます。のドキュメントでは
Control.Applicative
モジュールのドキュメントは次のように始まっています。
このモジュールは、ファンクタとモナドの中間の構造を記述します: それは純粋な式とシーケンシングを提供しますが、バインディングはありません。(技術的には、strong lax monoidal functorです)。
ふむ。
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)
...しかし、それはダメです。ひとつは、間違っていることです。もうひとつは、それは
醜い
. 試行錯誤を続けることができましたが、結局は
の上で動作するように複数の引数を持つ関数を持ち上げる方法はないことがわかりました。
Functor
. うっとおしい!
一方、簡単にできるのは
Maybe
's
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
通常の機能アプリケーションは、単純な用語の並列によって記述されるため、quot;解除アプリケーションをできるだけシンプルかつ自然にするために、この論文では、以下のものを紹介しています。
の中に持ち上げられたアプリケーションの代用となる接尾辞演算子を導入しました。
Functor
そして、そのために必要なものを提供するための型クラスです。
これらすべてから、次のようなことがわかります。
(<*>)
は単に関数アプリケーションを表します。では、なぜ空白の "並置演算子" と同じように発音するのでしょうか?
しかし、もしそれがあまり満足のいくものでないなら、私たちは
Control.Monad
モジュールもまた、モナドに対して同じことを行う関数を提供していることを観察することができます。
ap :: (Monad m) => m (a -> b) -> m a -> m b
ここで
ap
はもちろん、"apply" の略です。ということは、どんな
Monad
は
Applicative
であり、かつ
ap
は後者に存在する特徴のサブセットのみを必要とするため、おそらく次のように言うことができます。
であれば
(<*>)
が演算子でなかったなら、それは
ap
.
また、別の方向から物事をアプローチすることもできます。それは
Functor
というリフティング操作を行います。
fmap
を一般化したものだからです。
map
演算の一般化だからです。リストに対する関数はどのようなものかというと
(<*>)
? そこにあるのは
ap
がありますが、これはそれ自体では特に有用ではありません。
実際、リストにはおそらくもっと自然な解釈があります。次の型シグネチャを見たときに何が思い浮かぶでしょうか。
listApply :: [a -> b] -> [a] -> [b]
リストを並列に並べ、1つ目の関数を2つ目の対応する要素に適用するというアイデアは、何かとても魅力的です。残念ながら、私たちの古い友人である
Monad
にとっては残念なことですが、この単純な操作
はモナドの法則に反しています。
に違反します。しかし、これによって
Applicative
を作ることができ、その場合
(<*>)
は
を一般化したものを連ねることになります。
zipWith
と呼ぶことができるかもしれません。
fzipWith
?
このzippingのアイデアは、実は私たちを丸ごと連れてきてくれます。モノイダルファンクターについて、先ほどの数学の話を思い出してください。名前が示すように、これはモノイドとファンクタの構造を組み合わせる方法で、どちらも 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 ?
本当に "empty" を作成する方法があるとは思いたくないのです。
Functor
を作成する方法があるとは思いたくありませんし、任意の型の値を呼び出すこともできないので、型を固定することにします。
mfEmpty
として
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
の identity 要素と関係があることがわかります。
Monoid
の ID 要素に関連しているので、他の良い名前は、単位値、NULL 演算、またはそのようなものを示唆するものであるかもしれません。
長くなりましたので、まとめますと。
-
(<*>)
は単なる修正された関数アプリケーションなので、 "ap" または "apply" として読むか、通常の関数アプリケーションと同じように完全に消去することができます。 -
(<*>)
もおおよそ一般化してzipWith
をリスト上で一般化したもので、quot;zip functors with"として読むことができ、同じようにfmap
を"map a functor with"として読むのと同じです。
の意図に近いものです。
Applicative
型クラスの意図に近く、その名前が示すように、私が推奨するのはこれです。
実際、私は を自由に使うこと、そして発音しないこと、すべての持ち上げられたアプリケーション演算子 :
-
(<$>)
これは、単一引数関数をFunctor
-
(<*>)
これは、複数引数の関数をApplicative
-
(=<<)
に入る関数を束縛するものです。Monad
に入る関数を既存の計算機上に結合します。
この3つはすべて、本質的には、通常の関数アプリケーションに少しスパイスを加えたものです。
関連
-
[解決済み] 一般的に `{- |` で始まるHaskellのコメントは何を意味するのですか?
-
[解決済み] Hindley-Milnerのどの部分が理解できないのでしょうか?
-
[解決済み] .の違いは何ですか?(ドット)と$(ドルマーク)の違いは何ですか?
-
[解決済み】Weak Head Normal Formとは何ですか?
-
[解決済み】代数的なデータ型の代数を悪用する - なぜこれが有効なのか?
-
[解決済み】Node.jsに対するHaskellの対応について教えてください。
-
[解決済み] IntとIntegerの違いは何ですか?
-
[解決済み] Haskellのマルチコアプログラミングはどうなっているのか?
-
[解決済み] Haskellの関数合成(.)と関数応用($)イディオム:正しい使い方
-
[解決済み] Haskell型とデータコンストラクタ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] エラー haskell: スコープ内にありません。どういう意味ですか?
-
[解決済み] 一般的に `{- |` で始まるHaskellのコメントは何を意味するのですか?
-
[解決済み] Haskell - Ord aの型は何を意味するのでしょうか?
-
[解決済み】一般的なHaskellの演算子で発音可能な名前はありますか?[クローズド]
-
[解決済み] GHCiの複数行コマンド
-
[解決済み] CabalとStackの違いは何ですか?
-
[解決済み] レコードの単一フィールドを割り当て、残りのフィールドはコピーするための省略記法?
-
[解決済み] 無限リストでのfoldlとfoldrの動作
-
[解決済み] Haskellの初心者向けガイド?[終了しました]
-
[解決済み] リストからn番目の要素を得るには?