アプリケーティブは合成するが、モナドは合成しない 質問する

アプリケーティブは合成するが、モナドは合成しない 質問する

アプリケーティブは構成しますが、モナドは構成しません。

上記の記述はどういう意味ですか? また、どちらが優れているのでしょうか?

ベストアンサー1

タイプを比較すると

(<*>) :: 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

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

同様に、 s の追加のパワーが本当に必要な場合とMonad、 がサポートする厳格な計算構造で済む場合を認識することが重要ですApplicative

ちなみに、モナドの合成は難しいですが、必要以上に難しいかもしれません。 型は、-効果を使用して計算し、次に -効果を使用して-値を計算することm (n v)を示しています。この場合、-効果は -効果が始まる前に終了します(したがって、 が必要です)。-効果と -効果を交互に配置したいだけであれば、合成はおそらく要求しすぎです。mnvmnswapmn

おすすめ記事