유형을 비교하면
(<*>) :: Applicative a => a (s -> t) -> a s -> a t
(>>=) :: Monad m => m s -> (s -> m t) -> m t
우리는 두 개념을 구분하는 단서를 얻습니다. 즉, (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
어떤 효과의 결과를 사용하여 두 계산 (예 : 미사일 발사 및 휴전 협정 서명) 사이를 결정 하는 반면
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
중에서 선택 하고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
레이어간에 간섭이 없기 때문입니다.
그에 따라 Monad
s 의 추가 능력이 정말로 필요한 때와 Applicative
지원 하는 견고한 계산 구조에서 벗어날 수있는 때 를 인식하는 것이 좋습니다 .
참고로, 모나드를 작성하는 것은 어렵지만 필요한 것보다 많을 수 있습니다. 유형 m (n v)
은 m
-effects로 계산 한 다음 n
-effects로 v
-value 로 계산하는 것을 나타냅니다 . 여기서 m
-effects는 n
-effects가 시작 되기 전에 완료됩니다 (따라서 swap
). m
-effects와 n
-effects 를 인터리브하고 싶다면 , 구성은 아마도 너무 많은 질문 일 것입니다!