इस इकाई जो isomorphic को है पर विचार करें (Bool ->)
इकाई:
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
और इसे Maybe
मोनाड के साथ लिखें :
newtype Bad a = B (Maybe (Pair a))
मेरा दावा है कि Bad
वह सन्यासी नहीं हो सकता।
आंशिक प्रमाण:
fmap
संतुष्ट करने के लिए केवल एक ही तरीका है fmap id = id
:
instance Functor Bad where
fmap f (B x) = B $ fmap (fmap f) x
मठ के कानूनों को याद करें:
(1) join (return x) = x
(2) join (fmap return x) = x
(3) join (join x) = join (fmap join x)
की परिभाषा के लिए return x
, हमारे पास दो विकल्प हैं: B Nothing
या B (Just (P x x))
। यह स्पष्ट है कि x
(1) और (2) से लौटने की कोई उम्मीद नहीं है, हम फेंक नहीं सकते x
, इसलिए हमें दूसरा विकल्प चुनना होगा।
return' :: a -> Bad a
return' x = B (Just (P x x))
वह निकल जाता है join
। चूंकि कुछ ही संभावित इनपुट हैं, हम प्रत्येक के लिए एक मामला बना सकते हैं:
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)))))) = ???
चूंकि आउटपुट में टाइप होता है Bad a
, केवल विकल्प होते हैं B Nothing
या B (Just (P y1 y2))
जहां y1
, y2
को चुनना होता है x1 ... x4
।
मामलों (ए) और (बी) में, हमारे पास कोई प्रकार का मान नहीं है a
, इसलिए हम B Nothing
दोनों मामलों में लौटने के लिए मजबूर हैं ।
केस (E) का निर्धारण (1) और (2) मोनड कानूनों से होता है:
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))
आदेश वापस करने के B (Just (P y1 y2))
मामले (ई) में, इसका मतलब है कि हम चुनना चाहिए y1
या तो से x1
या x3
, और y2
से या तो x2
या 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))
इसी तरह, यह कहना है कि हम चुनना चाहिए y1
या तो से x1
या x2
, और y2
से या तो x3
या x4
। दोनों को मिलाकर, हम यह निर्धारित करते हैं कि (ई) का दाहिना हाथ होना चाहिए B (Just (P x1 x4))
।
अब तक यह सब अच्छा है, लेकिन समस्या तब आती है जब आप (सी) और (डी) के लिए दाहिने हाथ की तरफ भरने की कोशिश करते हैं।
प्रत्येक के लिए 5 संभव दाएं हाथ हैं, और कोई भी संयोजन काम नहीं करता है। मेरे पास अभी तक इसके लिए एक अच्छा तर्क नहीं है, लेकिन मेरे पास एक ऐसा कार्यक्रम है जो सभी संयोजनों का विस्तृत परीक्षण करता है:
{-# 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
दो साधुओं की रचना के लिए लिखना असंभव है सामान्य । लेकिन इससे कोई ठोस उदाहरण नहीं मिलता है।