응용 프로그램은 구성하지만 모나드는 구성하지 않습니다.
위의 진술은 무엇을 의미합니까? 그리고 언제 하나가 다른 것보다 선호됩니까?
답변
유형을 비교하면
(<*>) :: 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 를 인터리브하고 싶다면 , 구성은 아마도 너무 많은 질문 일 것입니다!
답변
응용 프로그램은 구성하지만 모나드는 구성하지 않습니다.
모나드 는 작성하지만 결과는 모나드가 아닐 수 있습니다. 반대로 두 가지 응용 프로그램의 구성은 반드시 응용 프로그램입니다. 원래 진술의 의도는 “적용 성은 구성하지만 모나드는 구성하지 않는다”는 것이 었습니다. ” Applicative
는 작성 중에 닫히고 닫혀 Monad
있지 않습니다.”
답변
당신은 applicatives있는 경우 A1
와 A2
, 그 유형을data A3 a = A3 (A1 (A2 a))
도 실용적이다 (당신은 일반적인 방법에서 이러한 경우를 쓸 수 있습니다).
반면에 모나드가 M1
있고 M2
유형 data M3 a = M3 (M1 (M2 a))
이 반드시 모나드가 아니라면 ( >>=
또는에 대한 합리적인 제네릭 구현이 없습니다.join
구성에 대한이).
한 가지 예는 유형일 수 있습니다 [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
유형에 대해 올바른 기능이 존재할 수 없습니다 .
답변
불행히도 우리의 진정한 목표 인 모나드 구성은 다소 어렵습니다. .. 사실, 우리는 실제로 어떤 의미에서 두 모나드의 연산만을 사용하여 위의 유형으로 조인 함수를 구성 할 수있는 방법이 없음을 실제로 증명할 수 있습니다 (증명에 대한 개요는 부록 참조). 우리가 컴포지션을 구성하는 유일한 방법은 두 구성 요소를 연결하는 몇 가지 추가 구성이있는 경우입니다.
답변
분배 법칙 솔루션 l : MN-> NM이면 충분합니다.
NM의 monadicity를 보장합니다. 이것을 보려면 유닛과 멀티가 필요합니다. 나는 다중에 초점을 맞출 것이다 (단위는 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이 관찰 한 바와 같이 , 우리는 양-백스터 방정식의 표현에 해당하는 육각형 조건이 필요합니다. 실제로 육각형 조건에서는 두 개의 다른 모나드가 일치합니다.