1. ホーム
  2. haskell

[解決済み] アプリケートは合成し、モナドは合成しない

2022-09-01 22:50:12

質問

アプリケートは合成し、モナドは合成しない。

上記の文章は何を意味しているのでしょうか?また、どのような場合に一方が他方より望ましいのでしょうか?

どのように解決するのですか?

種類を比較すると

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

弱い方の 'double-apply' はもっと簡単に定義できます。

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

は、レイヤー間の干渉がないため

の余分なパワーが本当に必要なときを認識するのは良いことです。 Monad の力が本当に必要なとき、そして Applicative がサポートする硬直した計算構造から逃れられるときです。

ちなみに、モナドの合成は難しいですが、必要以上かもしれないことに注意してください。型は m (n v) で計算することを示す m -で計算した後 n -の効果で v -の値に変換します。 m -の前に終了します。 n -が始まる前に終了します(そのため swap ). もし、単に m -という効果で n -のような効果がある場合、合成はあまりに無理があるかもしれません。