Appadativesは構成しますが、モナドは構成しません


110

Applicativeは構成しますが、モナドは構成しません。

上記のステートメントはどういう意味ですか?そして、いつ他の方が好ましいのですか?


5
この声明はどこから得ましたか?コンテキストを確認すると役立つ場合があります。
fuz

@FUZxxl:ツイッターのdebasishgから、たくさんの人から繰り返し聞いています。
missingfaktor 2011

3
多くのこのようなことを注意:@stephenテトリーApplicativesは実際に全体である家族MonadS、可能な構造の各「形状」の、すなわち1。ZipListではないMonadが、ZipList固定長のsがあります。Reader「構造」のサイズが環境タイプのカーディナリティーとして固定されている便利な特殊(またはそれは一般的ですか?)ケースです。
CAマッキャン

3
@CAMcCann同形になるまでモナドとなるように形状を修正した場合、それらのすべてのzippyアプリケーション(切り捨てられるかパディングされるかに関係なく)はモナドに制限されますReader。コンテナーの形状を修正すると、メモトライのように、位置からの関数が効果的にエンコードされます。ピーター・ハンコックは、対数の法則に従うので、そのような関手を「ナペリアン」と呼びます。
pigworker

4
@stephen tetley:他の例には、定数モノイドアプリケーション(モナドではなくモナドの構成)と、ユニット遅延アプリケーション(結合を認めない方がよい)があります。
pigworker

回答:


115

タイプを比較すると

(<*>) :: Applicative a => a (s -> t) -> a s -> a t
(>>=) :: Monad m =>       m s -> (s -> m t) -> m t

2つの概念を区別する手がかりがわかります。(s -> m t)のタイプのそれは、(>>=)の値sがの計算の動作を決定できることを示していますm t。モナドは、値と計算層の間の干渉を可能にします。(<*>)オペレータは、このような干渉を許容しない:関数引数の計算は、値に依存しません。これは本当に噛みます。比較する

miffy :: Monad m => m Bool -> m x -> m x -> m x
miffy mb mt mf = do
  b <- mb
  if b then mt else mf

いくつかの効果の結果を使用して、2つの計算(たとえば、ミサイルの発射と休戦への署名)を決定しますが、

iffy :: Applicative a => a Bool -> a x -> a x -> a x
iffy ab at af = pure cond <*> ab <*> at <*> af where
  cond b t f = if b then t else f

それらの値を使用するabとの間で選択するために 2つの計算atafの両方、恐らく悲劇的な影響を行う有します。

モナディックバージョンは(>>=)、の値から計算を選択するという追加の能力に本質的に依存しており、それは重要な場合があります。ただし、その力をサポートすると、モナドを構成するのが難しくなります。「ダブルバインド」を構築しようとすると

(>>>>==) :: (Monad m, Monad n) => m (n s) -> (s -> m (n t)) -> m (n t)
mns >>>>== f = mns >>-{-m-} \ ns -> let nmnt = ns >>= (return . f) in ???

ここまで到達しましたが、今ではレイヤーがすべて乱雑になっています。を持っているn (m (n t))ので、外側を取り除く必要がありnます。Alexandre Cが言うように、適切なものがあれば

swap :: n (m t) -> m (n t)

n内側を入れ替え、join他の入れ替えをするn

弱い「二重適用」は定義がはるかに簡単です

(<<**>>) :: (Applicative a, Applicative b) => a (b (s -> t)) -> a (b s) -> a (b t)
abf <<**>> abs = pure (<*>) <*> abf <*> abs

レイヤー間の干渉がないためです。

Monad同様に、いつsの追加のパワーが本当に必要なのか、いつApplicativeサポートする厳密な計算構造で問題を回避できるのかを認識するのは良いことです。

ちなみに、モナドの作成は難しいですが、必要以上に多いかもしれません。タイプm (n v)で計算を示しm次いでコンピューティング、効果- nの効果- v-value、m前効果-が完了n効果-は、(用したがって必要開始しますswap)。m-effectsとn-effects を交互に挿入したいだけの場合、コンポジションは多すぎて質問できないでしょう


3
iffyの例では、「abの値を使用して、atとafの2つの計算の値から選択し、おそらく悲劇的な影響のために両方を実行した」と述べています。Haskellの怠惰な性質はこれからあなたを守っていませんか?list =(\ btf-> if b then t else f):[]がある場合、次のステートメントを実行します:list <*> pure True <*> pure "hello" <*> pure(error "bad")。 ...「こんにちは」と表示され、エラーは発生しません。このコードはモナドほど安全でなく、制御されていませんが、この投稿は、アプリケーションが厳密な評価を引き起こすことを示唆しているようです。しかし、全体的に素晴らしい投稿です!ありがとう!
shj

7
あなたはまだ両方の効果を得ますが、純粋な(エラー「悪い」)には何もありません。一方、iffy(pure True)(pure "hello")(error "bad")を実行すると、miffyが回避できるエラーが発生します。さらに、iffy(純粋なTrue)(純粋な0)[1,2]のようなものを試すと、[0]ではなく[0,0]が得られます。Applicativesは、固定された一連の計算を構築するという点で、それらについて一種の厳密性を持っていますが、これらの計算から得られたは、ご存じのように遅延して結合されます。
pigworker

どのモナドについても、モナド変換子mnいつでも作成mtしてn (m t)使用することができるというのは本当mt n tですか?したがって、いつでもモナドを作成できますが、トランスフォーマーを使用すると、さらに複雑になりますか?
ron

4
そのようなトランスフォーマーはしばしば存在しますが、私の知る限り、それらを生成する正規の方法はありません。多くの場合、さまざまなモナドからインターリーブされた効果を解決する方法について真の選択があります。典型的な例は例外と状態です。例外は状態の変化をロールバックすべきか?どちらの選択肢にも代わりがあります。そうは言っても、「任意のインターリーブ」を表す「フリーモナド」というものがあります。data Free f x = Ret x | Do (f (Free f x))、それからdata (:+:) f g x = Inl (f x) | Tnr (g x)、そして考えなさいFree (m :+: n)。これにより、インターリーブの実行方法の選択が遅れます。
pigworker '19年

@pigworker遅延/厳密な議論について。アプリケーションは、計算から効果を制御することはできないと思いますが、効果層は後の値を評価しないことを非常によく決定できます。(適用可能な)パーサーの場合、これは、パーサーが早期に失敗した場合、後続のパーサーは入力に対して評価/適用されないことを意味します。以下のためのMaybe初期のことは、この手段Nothingの評価抑制しますa後に/それに続くのはJust a。これは正しいです?
ziggystar 2015年

75

Applicativeは構成しますが、モナドは構成しません。

モナド作成しますが、結果はモナドではない可能性があります。対照的に、2つのアプリケーションの構成は必ずアプリケーションです。元のステートメントの意図は「適用可能性は構成するが、モナドネスは構成しない」であったと私は推測します。「作文でApplicativeは閉鎖されており、そうでMonadはない」と言い換えた。


24
さらに、任意の2つのアプリケーションは完全に機械的な方法で構成されますが、2つのモナドの構成によって形成されるモナドはその構成に固有です。
Apocalisp 2011

12
さらに、モナドは他の方法で構成されます。2つのモナドの積はモナドです。これは、何らかの分配法を必要とする副産物だけです。
エドワードKMETT 2011

@Apocalisp、コメントを含めて、これは最良かつ最も簡潔な答えです。
Paul Draper、

39

applicatives A1A2がある場合、タイプdata A3 a = A3 (A1 (A2 a))もapplicativeです(このようなインスタンスは一般的な方法で記述できます)。

一方、モナドがM1ありM2、型data M3 a = M3 (M1 (M2 a))がモナドであるとは限りません(合成のための、>>=またはjoin合成のための賢明な一般的な実装はありません)。

1つの例として、型があります[Int -> a](ここでは、型コンストラクタ[](->) Intで構成します。どちらもモナドです)。簡単に書ける

app :: [Int -> (a -> b)] -> [Int -> a] -> [Int -> b]
app f x = (<*>) <$> f <*> x

そして、それはどんなアプリケーションにも一般化されます:

app :: (Applicative f, Applicative f1) => f (f1 (a -> b)) -> f (f1 a) -> f (f1 b)

しかし、賢明な定義はありません

join :: [Int -> [Int -> a]] -> [Int -> a]

これに確信がない場合は、次の式を検討してください。

join [\x -> replicate x (const ())]

返されるリストの長さは、整数が提供される前に設定する必要がありますが、正しい長さは提供される整数によって異なります。したがって、joinこのタイプの正しい関数は存在できません。


1
...関数が実行するときにモナドを避けますか?
アンドリュークック

2
@andrew、ファンクターを意味する場合は、はい、ファンクターはより単純で、十分な場合に使用する必要があります。常にそうであるとは限らないことに注意してください。たとえばIO、a Monadがないと、プログラムするのが非常に難しくなります。:)
Rotsor

17

残念ながら、私たちの本当の目標であるモナドの構成はかなり難しいです。..実際、ある意味で、2つのモナドの演算のみを使用して上記のタイプの結合関数を構築する方法がないことを実際に証明できます(証明の概要については付録を参照してください)。したがって、コンポジションを形成したい唯一の方法は、2つのコンポーネントをリンクする追加の構造がある場合のみです。

モナドの作成、http: //web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf


4
Tl; drせっかちな読者のために:モナドを作成できますif(f?)自然な変換を提供できますswap : N M a -> M N a
Alexandre C.

@Alexandre C .:「もし」なら、私はそう思う。すべてのモナド変換子が直接ファンクタ構成で記述されるわけではありません。例えば、ContT r m aではありませんどちらm (Cont r a)Cont r (m a)、そしてStateT s m aおおよそですReader s (m (Writer s a))
CAマッキャン

@CAマッキャン:(Mモナド、Nモナド、MNモナド、NMモナド)から(スワップが存在する:MN-> NMナチュラル)に到達できないようです。それでは、とりあえず "if"に固執しましょう(おそらく回答が論文にあるので、すぐに調べたと告白する必要があります)
Alexandre C.

1
@Alexandre C .:構成がモナドであることを指定するだけでは、とにかく十分ではない可能性があります。2つの部分を全体と関連付ける何らかの方法も必要です。の存在はswap、構成が2つが何らかの形で「協力」できるようにすることを意味します。また、これsequenceは一部のモナドの「スワップ」の特殊なケースです。そうですflip、実際に。
CAマッキャン

7
(適切にpedをswap :: N (M x) -> M (N x)使用して)を前と後ろに挿入し、から移動し、次にコンポジットのを使用してを取得できるように、それを書くには私に見えます。returnsfmapMNN (M x) -> M (N (M (N x)))joinM (N x)
pigworker

7

分配法の解l:MN-> NMで十分

NMのモナディシティを保証するため。これを見るには、ユニットとマルチが必要です。マルチに焦点を当てます(単位はunit_N unitM)

NMNM - l -> NNMM - mult_N mult_M -> NM

これは、MNがモナドであることを保証するものではありませ

ただし、重要な観察は、分散法による解決策がある場合に効果を発揮します。

l1 : ML -> LM
l2 : NL -> LN
l3 : NM -> MN

したがって、LM、LN、MNはモナドです。LMNがモナドかどうか(

(MN)L-> L(MN)またはN(LM)->(LM)N

これらのマップを作成するのに十分な構造があります。ただし、Eugenia Chengが観察しているように、どちらかの構造の単一性を保証するために、六角形の条件(Yang-Baxter方程式の表現に相当する)が必要です。実際、六角形の条件では、2つの異なるモナドが一致します。


9
これはおそらく素晴らしい答えですが、私の頭の上にはすごい音がしました。
Dan Burton、

1
これは、Applicativeとhaskellタグという用語を使用しているため、これはhaskellに関する質問ですが、回答は別の表記法になっているためです。
コードショット2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.