2016-11-11 9 views
3

:AccValidation에 Monad 인스턴스가없는 이유는 무엇입니까? <a href="https://hackage.haskell.org/package/validation" rel="nofollow noreferrer"><code>validation</code></a> 패키지의 문서에서

AccValidation 데이터 형식 Either 동형이지만, 에러 측에 축적 Applicative 인스턴스를 갖는다. 즉, 두 개 이상의 오류가 발생하면 Semigroup 연산을 사용하여 오류가 추가됩니다.

Applicative 인스턴스의 결과로 해당 Bind 또는 Monad 인스턴스가 없습니다. AccValidation은 "모나드가 아닌 응용 펑터"의 예입니다.

왜 이것이 결과인지는 분명하지 않습니다. AccValidationMonad 인스턴스가 Either처럼 동작한다고 생각합니다. 무엇이 불법입니까?

+0

당신은 어떤 상상을하고 있습니까? '모두'에 대한 적용 가능한 인스턴스는 오류가없는쪽에 누적됩니다. – Alec

+2

초기 단계에서 실패한 경우 나중에 "단계"를 실행할 수 없습니다. Applicative를 사용하면 성공적인 결과를 얻기 위해 적용 할 수 없더라도 나중 단계를 여전히 * 계산 * 할 수 있습니다. 따라서 나중 단계의 계산이 실패했는지 알 수 있습니다. Monad를 사용하면 각 단계에서 다음 단계가 반환되므로 나중에 단계가 무엇인지 모릅니다. – immibis

+0

@Alec '어느 쪽인가'에 대한 신청자는 'AccValidation'이 누적되는 것과 동일한 의미로 '누적'하지 않습니다. 맞습니까? –

답변

4

기계적으로는, AccValidationEither -ish Monad 인스턴스는 의미

-- The (Monoid err) context is not used for anything, 
-- it's just there to satisfy the Applicative super-instance 
instance (Monoid err) => Monad (AccValidation err) where 
    return = AccSuccess 
    AccFailure err >>= f = AccFailure err 
    AccSuccess x >>= f = f x 

우리가 <*> = ap의 모나드 법칙을 나누기

AccFailure err1 <*> AccFailure err2 = AccFailure (err1 <> err2) 
AccFailure err1 `ap` AccFailure err2 = AccFailure err1 

이 될 것입니다.

모나드에서는 연산의 효과 (즉, 검증 실패)가 이전에 바인드 된 결과에 의존 할 수 있기 때문에 직관적으로 모나드를 만들 수 없습니다. 그러나 실패의 경우에는 결과가 없습니다. 그래서 Either(>>=)의 오른쪽에있는 후속 기능에 공급할 것이 없으므로이 경우 오류로 인한 단락보다는 선택의 여지가 없습니다.

이것은 효과 (이 경우 유효성 검사 실패)가 다른 결과에 의존 할 수없는 응용 펑터와는 현저한 차이가 있습니다. 따라서 결과를 제공하지 않고 모든 유효성 검사 실패를 얻을 수 있습니다 에서?) 한 계산에서 다른 계산.

+0

은'ap'가 아니며'fmap/<$>'와 같은'<*>'의 별칭일까요? – notgiorgi

+1

@notgiorgi 정확하지 않습니다. ['ap'는'Monad' 방법을 사용하여 구현 된'(<*>) '입니다 (https://hackage.haskell.org/package/base-4.9.1.0/docs/src/GHC.Base.html#ap). 'ap'는'(<*>)'에'liftM'이'fmap'에 대해서 무엇인가입니다. – duplode

5

The (<*>) = ap exigence(>>=) 약관에 명시 할 수 있습니다

u <*> v = u >>= \f -> fmap f v -- [1] 

을 이제 AccValidationFunctorApplicative 인스턴스를 제공, 우리는이 :

fmap _ (AccFailure e) = AccFailure e -- [2] 

AccFailure e1 <*> AccFailure e2 = AccFailure (e1 <> e2) -- [3] 

우리가 u = AccFailure e1를 한 경우와 v = AccFailure e2에서 [ 1], 우리는 다음을 얻습니다 :

AccFailure e1 <*> AccFailure e2 = AccFailure e1 >>= \f -> fmap f (AccFailure e2) 
012 3,516,

대입 [2]와 [3] 즉, 우리 유도로에 :

AccFailure (e1 <> e2) = AccFailure e1 >>= \_ -> AccFailure e2 -- [4] 

문제는 [4]와 같은 보유 (>>=) 것을 작성하는 것이 불가능하다는 것이다. 왼쪽은 e2 값에 따라 달라지며, 오른쪽 값은 \_ -> AccFailure e2 :: Semigroup e => a -> AccValidation e b을 적용해야합니다. 그러나 적용 할 수있는 것은 없습니다. 특히 e1의 유형이 잘못되었습니다. (이 부분에 대한 더 자세한 설명은 Cactus의 대답의 마지막 두 단락을 참조하십시오.) 따라서 AccValidation에 과 일치하는 Monad 인스턴스를 제공 할 방법이 없습니다.