アプリケーティブは構成しますが、モナドは構成しません。
上記の記述はどういう意味ですか? また、どちらが優れているのでしょうか?
ベストアンサー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 つの計算at
とaf
、両方を実行すると、おそらく悲劇的な結果になります。
モナド版は、本質的には、値から計算を選択するための追加のパワーに依存しており(>>=)
、これは重要です。しかし、そのパワーをサポートすると、モナドの合成が難しくなります。「二重拘束」を構築しようとすると、
(>>>>==) :: (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)
を示しています。この場合、-効果は -効果が始まる前に終了します(したがって、 が必要です)。-効果と -効果を交互に配置したいだけであれば、合成はおそらく要求しすぎです。m
n
v
m
n
swap
m
n