Betrachten Sie diese Monade, die zur (Bool ->)Monade isomorph ist :
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
und komponiere es mit der MaybeMonade:
newtype Bad a = B (Maybe (Pair a))
Ich behaupte, das Badkann keine Monade sein.
Teilnachweis:
Es gibt nur einen Weg zu definieren fmap, der erfüllt fmap id = id:
instance Functor Bad where
fmap f (B x) = B $ fmap (fmap f) x
Erinnern Sie sich an die Monadengesetze:
(1) join (return x) = x
(2) join (fmap return x) = x
(3) join (join x) = join (fmap join x)
Für die Definition von return xhaben wir zwei Möglichkeiten: B Nothingoder B (Just (P x x)). Es ist klar , dass wir, um Hoffnung auf eine Rückkehr xvon (1) und (2) zu haben, nicht wegwerfen können x, also müssen wir die zweite Option wählen.
return' :: a -> Bad a
return' x = B (Just (P x x))
Das geht join. Da es nur wenige mögliche Eingaben gibt, können wir für jede einen Fall machen:
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)))))) = ???
Da der Ausgangstyp hat Bad a, sind die einzigen Optionen B Nothingoder B (Just (P y1 y2))wo y1, y2müssen ausgewählt werdenx1 ... x4 .
In den Fällen (A) und (B) haben wir keine Werte vom Typ a, daher müssen wir zurückkehrenB Nothing in beiden Fällen zurückkehren.
Fall (E) wird durch die Monadengesetze (1) und (2) bestimmt:
-- apply (1) to (B (Just (P y1 y2)))
join (return' (B (Just (P y1 y2))))
= -- using our definition of return'
join (B (Just (P (B (Just (P y1 y2))) (B (Just (P y1 y2))))))
= -- from (1) this should equal
B (Just (P y1 y2))
Um B (Just (P y1 y2))in Fall (E) zurückzukehren, bedeutet dies, dass wir y1entweder x1oder oder x3und y2entweder x2oder auswählen müssen x4.
-- apply (2) to (B (Just (P y1 y2)))
join (fmap return' (B (Just (P y1 y2))))
= -- def of fmap
join (B (Just (P (return y1) (return y2))))
= -- def of return
join (B (Just (P (B (Just (P y1 y1))) (B (Just (P y2 y2))))))
= -- from (2) this should equal
B (Just (P y1 y2))
Ebenso heißt es, dass wir y1entweder x1oder oder x2und y2entweder x3oder auswählen müssen x4. Wenn wir beide kombinieren, bestimmen wir, dass die rechte Seite von (E) sein muss B (Just (P x1 x4)).
Bisher ist alles gut, aber das Problem tritt auf, wenn Sie versuchen, die rechten Seiten für (C) und (D) auszufüllen.
Es gibt jeweils 5 mögliche rechte Seiten, und keine der Kombinationen funktioniert. Ich habe noch kein gutes Argument dafür, aber ich habe ein Programm, das alle Kombinationen ausführlich testet:
{-# 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
-- The only definition that could possibly work.
unit :: a -> Bad a
unit x = B (Just (P x x))
-- Number of possible definitions of join for this type. If this equals zero, no monad for you!
joins :: Integer
joins = sum $ do
-- Try all possible ways of handling cases 3 and 4 in the definition of join below.
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 -- no choice
join (B (Just (P (B Nothing) (B Nothing)))) = B Nothing -- again, no choice
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)) -- derived from monad laws
-- We've already learnt all we can from these two, but I decided to leave them in anyway.
guard $ all (\x -> join (unit x) == x) bad1
guard $ all (\x -> join (fmap unit x) == x) bad1
-- This is the one that matters
guard $ all (\x -> join (join x) == join (fmap join x)) bad3
return 1
main = putStrLn $ show joins ++ " combinations work."
-- Functions for making all the different forms of Bad values containing distinct Ints.
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'')
joinfür die Komposition von zwei Monaden in zu schreiben allgemein . Dies führt jedoch zu keinen konkreten Beispielen.