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 Maybe
Monade:
newtype Bad a = B (Maybe (Pair a))
Ich behaupte, das Bad
kann 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 x
haben wir zwei Möglichkeiten: B Nothing
oder B (Just (P x x))
. Es ist klar , dass wir, um Hoffnung auf eine Rückkehr x
von (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 Nothing
oder B (Just (P y1 y2))
wo y1
, y2
mü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 y1
entweder x1
oder oder x3
und y2
entweder x2
oder 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 y1
entweder x1
oder oder x2
und y2
entweder x3
oder 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'')
join
für die Komposition von zwei Monaden in zu schreiben allgemein . Dies führt jedoch zu keinen konkreten Beispielen.