이 질문에 대한보다 체계적인 접근 방식을 제안하고 "하단"값이나 무한한 데이터 유형 또는 이와 유사한 것을 사용하지 않는 예제를 보여 드리고자합니다.
언제 타입 생성자가 타입 클래스 인스턴스를 갖지 못합니까?
일반적으로 형식 생성자가 특정 형식 클래스의 인스턴스를 가질 수없는 데는 두 가지 이유가 있습니다.
- 유형 클래스에서 필수 메소드의 유형 서명을 구현할 수 없습니다.
- 형식 서명을 구현할 수 있지만 필요한 법률을 충족 할 수는 없습니다.
첫 번째 종류의 예는 두 번째 종류의 예보다 쉽습니다. 첫 번째 종류의 경우 주어진 유형 서명으로 함수를 구현할 수 있는지 여부를 확인하기 만하면되고, 두 번째 종류의 경우 구현이 없음을 증명해야합니다. 법을 충족시킬 수 있습니다.
구체적인 예
이것은 입력 파라미터에 대하여 contrafunctor 아닌 펑이다 a
때문에, a
contravariant 위치. type signature 형식의 함수를 구현하는 것은 불가능합니다 (a -> b) -> F z a -> F z b
.
형식 서명을 fmap
구현할 수 있지만 합법적 인 functor가 아닌 형식 생성자 :
data Q a = Q(a -> Int, a)
fmap :: (a -> b) -> Q a -> Q b
fmap f (Q(g, x)) = Q(\_ -> g x, f x) -- this fails the functor laws!
이 예제의 흥미로운 점은 반 변형 위치에서 사용하기 때문에 functor가 될 수는 없지만 올바른 유형을 구현할 수 있다는 것 입니다. 따라서 위에 표시된 이 구현 은 오해의 소지가 있습니다. 올바른 유형 서명이 있지만 (이 유형 서명의 유일한 가능한 구현이라고 생각합니다) functor 법률은 충족되지 않습니다. 예를 들어 ≠ 이므로 is 이지만 is 입니다.fmap
F
a
fmap
fmap id
id
let (Q(f,_)) = fmap id (Q(read,"123")) in f "456"
123
let (Q(f,_)) = id (Q(read,"123")) in f "456"
456
실제로, F
그것은 옹호자 일뿐입니다-그것은 펑 터나 피임 펀더가 아닙니다.
의 형식 서명을 pure
구현할 수 없기 때문에 적용 할 수없는 합법적 인 functor : Writer 모나드를 가져와 모노 이드 여야 (a, w)
하는 제약 조건을 제거하십시오 w
. 그런 다음 (a, w)
out of type 값을 구성하는 것은 불가능합니다 a
.
의 형식 서명을 <*>
구현할 수 없기 때문에 적용되지 않는 functor : data F a = Either (Int -> a) (String -> a)
.
타입 클래스 메소드를 구현할 수 있지만 합법적이지 않은 functor :
data P a = P ((a -> Int) -> Maybe a)
유형 생성자 P
는 a
공변량 위치에서만 사용하기 때문에 functor 입니다.
instance Functor P where
fmap :: (a -> b) -> P a -> P b
fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))
형식 서명의 유일한 구현은 <*>
항상 다음을 반환하는 함수입니다 Nothing
.
(<*>) :: P (a -> b) -> P a -> P b
(P pfab) <*> (P pa) = \_ -> Nothing -- fails the laws!
그러나이 구현은 적용 펑터에 대한 신원 법을 충족시키지 않습니다.
Applicative
Monad
유형 시그니처를 bind
구현할 수 없기 때문에 그렇지 않은 functor
나는 그런 예를 모른다!
Applicative
Monad
유형 시그니처를 bind
구현할 수 있어도 법을 충족시킬 수 없기 때문에 펑터가 아닙니다 .
이 예제는 상당히 많은 논의를했기 때문에이 예제를 올바르게 증명하는 것이 쉽지 않다고 말하는 것이 안전합니다. 그러나 여러 사람들이 다른 방법으로 독립적으로 이것을 확인했습니다. 참조 |된다`데이터 증서는 빈 = 모나드 페어? 추가 토론.
data B a = Maybe (a, a)
deriving Functor
instance Applicative B where
pure x = Just (x, x)
b1 <*> b2 = case (b1, b2) of
(Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
_ -> Nothing
합법적 인 Monad
사례 가 없음을 증명하는 것은 다소 성가신 일 입니다. 비모 노드 동작의 이유 bind
는 함수 f :: a -> B b
가를 반환 Nothing
하거나 Just
다른 값을 반환 할 때 자연스럽게 구현할 수 있는 방법이 없기 때문 입니다 a
.
Maybe (a, a, a)
모나드가 아닌를 고려 하고 구현을 시도하는 것이 더 명확 할 것 join
입니다. 직관적으로 합리적인 구현 방법이 없다는 것을 알게 될 것입니다 join
.
join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
join Nothing = Nothing
join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
-- etc.
로 표시된 경우 ???
, 우리는 Just (z1, z2, z3)
6 가지 유형의 값 중에서 합리적이고 대칭적인 방식으로 생산할 수 없음이 분명해 보인다 a
. 우리는 확실히이 6 가지 값 중 임의의 부분 집합을 선택할 수 있습니다 Maybe
. 귀국 Nothing
도 법률을 충족하지 않습니다.
- 모나드 가 아니지만 연관성 이있는 트리와 유사한 데이터 구조-신분법에
bind
실패합니다.
일반적인 나무와 같은 모나드 (또는 "펑터 모양의 가지가있는 나무")는 다음과 같이 정의됩니다.
data Tr f a = Leaf a | Branch (f (Tr f a))
이것은 functor에 대한 무료 모나드 f
입니다. 데이터의 모양은 각 분기점이 하위 트리의 "기능이 많은"트리입니다. 표준 이진 트리는로 얻을 수 있습니다 type f a = (a, a)
.
우리가 functor 모양의 잎을 f
만들어서이 데이터 구조를 수정하면 , 우리는 내가 "세미 모나드 (semimonad)"라고 부르는 것을 얻습니다. 그것은 bind
자연 성과 연관성 법칙을 만족 시키지만 그 pure
방법 은 신분법 중 하나에 실패합니다. "세미 모나드는 endofunctors의 범주에서 세미 그룹입니다, 문제는 무엇입니까?" 이것은 타입 클래스 Bind
입니다.
간단하게하기 위해 join
메소드 대신 다음을 정의합니다 bind
.
data Trs f a = Leaf (f a) | Branch (f (Trs f a))
join :: Trs f (Trs f a) -> Trs f a
join (Leaf ftrs) = Branch ftrs
join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)
가지 이식은 표준이지만 잎 이식은 비표준이며 Branch
. 이것은 연관성 법의 문제는 아니지만 신원 법 중 하나를 위반합니다.
다항식 유형에는 언제 모나드 인스턴스가 있습니까?
어느 쪽도 아니 펑의 Maybe (a, a)
와 Maybe (a, a, a)
합법적 할 수는 없으며, Monad
그들은 분명히 있지만, 인스턴스를 Applicative
.
더 -이 펑은 속임수가 없다 Void
거나 bottom
어디서든, 어떤 까다로운 게으름 / 엄격함, 아니 무한 구조 및 어떤 타입의 클래스 제약 조건을. Applicative
인스턴스는 완전히 표준입니다. 이러한 기능에 대해 기능 return
과 bind
구현이 가능하지만 모나드의 법칙을 만족 시키지는 않습니다. 다시 말해, 이러한 기능은 특정 구조가 없기 때문에 모나드가 아닙니다 (그러나 정확히 무엇이 없는지 이해하기는 어렵습니다). 예를 들어, functor를 조금만 변경하면 모나드로 만들 수 있습니다. data Maybe a = Nothing | Just a
는 모나드입니다. 또 다른 유사한 functor data P12 a = Either a (a, a)
도 모나드입니다.
다항식 모나드 구성
일반적으로 다음은 Monad
다항식 유형에서 합법적 인 내용을 생성하는 일부 구성입니다 . 이 모든 구성에서 M
모나드는 다음과 같습니다.
type M a = Either c (w, a)
w
monoid는 어디에 있습니까
type M a = m (Either c (w, a))
m
모나드는 어디에 있고 w
어떤 모노 이드인가
type M a = (m1 a, m2 a)
모나드는 어디에 m1
있고m2
type M a = Either a (m a)
m
모나드는 어디에 있습니까
첫 번째 건설은 WriterT w (Either c)
이고 두 번째 건설은 WriterT w (EitherT c m)
입니다. : 세 번째 구성은 모나드의 성분 와이즈 제품 pure @M
의 성분 와이즈 곱으로 정의 pure @m1
하고 pure @m2
, 그리고 join @M
(예를 들어 간 제품 데이터를 생략함으로써 정의 m1 (m1 a, m2 a)
에 매핑 m1 (m1 a)
튜플의 두 번째 부분을 생략함으로써)
join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))
네 번째 구조는 다음과 같이 정의됩니다.
data M m a = Either a (m a)
instance Monad m => Monad M m where
pure x = Left x
join :: Either (M m a) (m (M m a)) -> M m a
join (Left mma) = mma
join (Right me) = Right $ join @m $ fmap @m squash me where
squash :: M m a -> m a
squash (Left x) = pure @m x
squash (Right ma) = ma
나는 네 가지 구조물 모두 합법적 인 모나드를 생산하는지 확인했습니다.
나는 추측 다항식 모나드에 대한 다른 구조물이 없음. 예를 들어, 펑 터는 Maybe (Either (a, a) (a, a, a, a))
이러한 구성을 통해 얻지 못하므로 모나 딕이 아닙니다. 그러나 Either (a, a) (a, a, a)
이 세 가지 모나드의 제품에 동형 때문에 모나드이다 a
, a
하고 Maybe a
. 또한, Either (a,a) (a,a,a,a)
그것은의 제품에 동형 때문에 모나드이다 a
하고 Either a (a, a, a)
.
위에 표시된 네 가지 구성을 통해 a
예를 들어 여러 가지 수의 제품에 대한 합계를 얻을 Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a))
수 있습니다. 이러한 모든 유형 생성자는 하나 이상의 Monad
인스턴스를 갖습니다 .
물론 그러한 모나드에 어떤 유스 케이스가 존재할 수 있는지는 여전히 남아 있습니다. 또 다른 문제는 Monad
구성 1-4를 통해 파생 된 인스턴스가 일반적으로 고유하지 않다는 것입니다. 예를 들어, 형식 생성자 에는 두 가지 방식으로 인스턴스 type F a = Either a (a, a)
가 제공 될 수 있습니다 Monad
. 모나드를 사용하는 구성 4 (a, a)
및 유형 isomorphism을 사용하는 구성 3 Either a (a, a) = (a, Maybe a)
. 다시 한번, 이러한 구현에 대한 사용 사례를 찾는 것은 명백하지 않습니다.
임의의 다항식 데이터 유형, Monad
인스턴스 가 있는지 여부를 인식하는 방법에 대한 질문이 남아 있습니다 . 다항식 모나드에 대한 다른 구성이 없음을 증명하는 방법을 모르겠습니다. 나는 지금까지이 질문에 대답 할 이론이 없다고 생각합니다.
* -> *
) 를 만들 수 있습니까?fmap