Hãy xem xét đơn nguyên này là đồng cấu với (Bool ->)
đơn nguyên:
data Pair a = P a a
instance Functor Pair where
fmap f (P x y) = P (f x) (f y)
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where P x _ = f a
P _ y = f b
và soạn nó với Maybe
monad:
newtype Bad a = B (Maybe (Pair a))
Tôi khẳng định đó Bad
không thể là đơn nguyên.
Chứng minh một phần:
Chỉ có một cách để xác định fmap
điều đó thỏa mãn fmap id = id
:
instance Functor Bad where
fmap f (B x) = B $ fmap (fmap f) x
Nhắc lại các luật đơn nguyên:
(1) join (return x) = x
(2) join (fmap return x) = x
(3) join (join x) = join (fmap join x)
Đối với định nghĩa của return x
, chúng ta có hai lựa chọn: B Nothing
hoặc B (Just (P x x))
. Rõ ràng là để có hy vọng quay trở lại x
từ (1) và (2), chúng ta không thể vứt bỏ x
, vì vậy chúng ta phải chọn phương án thứ hai.
return' :: a -> Bad a
return' x = B (Just (P x x))
Rời đi join
. Vì chỉ có một số đầu vào khả thi, chúng tôi có thể đưa ra một trường hợp cho mỗi:
join :: Bad (Bad a) -> Bad a
(A) join (B Nothing) = ???
(B) join (B (Just (P (B Nothing) (B Nothing)))) = ???
(C) join (B (Just (P (B (Just (P x1 x2))) (B Nothing)))) = ???
(D) join (B (Just (P (B Nothing) (B (Just (P x1 x2)))))) = ???
(E) join (B (Just (P (B (Just (P x1 x2))) (B (Just (P x3 x4)))))) = ???
Vì đầu ra có loại Bad a
, các tùy chọn duy nhất là B Nothing
hoặc B (Just (P y1 y2))
ở đâu y1
, y2
phải được chọn từ x1 ... x4
.
Trong trường hợp (A) và (B), chúng tôi không có giá trị kiểu nào a
, vì vậy chúng tôi buộc phải trả về B Nothing
trong cả hai trường hợp.
Trường hợp (E) được xác định bởi (1) và (2) luật đơn nguyên:
join (return' (B (Just (P y1 y2))))
=
join (B (Just (P (B (Just (P y1 y2))) (B (Just (P y1 y2))))))
=
B (Just (P y1 y2))
Để trả về B (Just (P y1 y2))
trong trường hợp (E), điều này có nghĩa là chúng ta phải chọn y1
một trong hai x1
hoặc x3
, và y2
từ một trong hai x2
hoặc x4
.
join (fmap return' (B (Just (P y1 y2))))
=
join (B (Just (P (return y1) (return y2))))
=
join (B (Just (P (B (Just (P y1 y1))) (B (Just (P y2 y2))))))
=
B (Just (P y1 y2))
Tương tự như vậy, điều này nói rằng chúng ta phải chọn y1
từ một trong hai x1
hoặc x2
, và y2
từ một trong hai x3
hoặc x4
. Kết hợp cả hai, chúng tôi xác định rằng phía bên phải của (E) phải là B (Just (P x1 x4))
.
Cho đến nay, tất cả đều tốt, nhưng vấn đề xảy ra khi bạn cố gắng điền vào các cạnh bên phải cho (C) và (D).
Có 5 bên tay phải có thể có cho mỗi bên và không tổ hợp nào hoạt động. Tôi chưa có lập luận tốt cho điều này, nhưng tôi có một chương trình kiểm tra toàn diện tất cả các kết hợp:
{-# LANGUAGE ImpredicativeTypes, ScopedTypeVariables #-}
import Control.Monad (guard)
data Pair a = P a a
deriving (Eq, Show)
instance Functor Pair where
fmap f (P x y) = P (f x) (f y)
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where P x _ = f a
P _ y = f b
newtype Bad a = B (Maybe (Pair a))
deriving (Eq, Show)
instance Functor Bad where
fmap f (B x) = B $ fmap (fmap f) x
unit :: a -> Bad a
unit x = B (Just (P x x))
joins :: Integer
joins = sum $ do
let ways = [ \_ _ -> B Nothing
, \a b -> B (Just (P a a))
, \a b -> B (Just (P a b))
, \a b -> B (Just (P b a))
, \a b -> B (Just (P b b)) ] :: [forall a. a -> a -> Bad a]
c3 :: forall a. a -> a -> Bad a <- ways
c4 :: forall a. a -> a -> Bad a <- ways
let join :: forall a. Bad (Bad a) -> Bad a
join (B Nothing) = B Nothing
join (B (Just (P (B Nothing) (B Nothing)))) = B Nothing
join (B (Just (P (B (Just (P x1 x2))) (B Nothing)))) = c3 x1 x2
join (B (Just (P (B Nothing) (B (Just (P x3 x4)))))) = c4 x3 x4
join (B (Just (P (B (Just (P x1 x2))) (B (Just (P x3 x4)))))) = B (Just (P x1 x4))
guard $ all (\x -> join (unit x) == x) bad1
guard $ all (\x -> join (fmap unit x) == x) bad1
guard $ all (\x -> join (join x) == join (fmap join x)) bad3
return 1
main = putStrLn $ show joins ++ " combinations work."
bad1 :: [Bad Int]
bad1 = map fst (bad1' 1)
bad3 :: [Bad (Bad (Bad Int))]
bad3 = map fst (bad3' 1)
bad1' :: Int -> [(Bad Int, Int)]
bad1' n = [(B Nothing, n), (B (Just (P n (n+1))), n+2)]
bad2' :: Int -> [(Bad (Bad Int), Int)]
bad2' n = (B Nothing, n) : do
(x, n') <- bad1' n
(y, n'') <- bad1' n'
return (B (Just (P x y)), n'')
bad3' :: Int -> [(Bad (Bad (Bad Int)), Int)]
bad3' n = (B Nothing, n) : do
(x, n') <- bad2' n
(y, n'') <- bad2' n'
return (B (Just (P x y)), n'')
join
cho thành phần của hai monads trong nói chung . Nhưng điều này không dẫn đến bất kỳ ví dụ cụ thể nào .