Etwas durch den folgenden Code mystifiziert. In der Nicht-Spielzeug-Version des Problems versuche ich eine monadische Berechnung in einer Monade durchzuführen, deren Werte nur innerhalb von IO konstruiert werden können. Scheint so, als ob die Magie hinter IO solche Berechnungen streng macht, aber ich kann nicht herausfinden, wie genau das passiert.IO-Monade verhindert Kurzschlüsse von eingebetteten MapM?
Der Code:
data Result a = Result a | Failure deriving (Show)
instance Functor Result where
fmap f (Result a) = Result (f a)
fmap f Failure = Failure
instance Applicative Result where
pure = return
(<*>) = ap
instance Monad Result where
return = Result
Result a >>= f = f a
Failure >>= _ = Failure
compute :: Int -> Result Int
compute 3 = Failure
compute x = traceShow x $ Result x
compute2 :: Monad m => Int -> m (Result Int)
compute2 3 = return Failure
compute2 x = traceShow x $ return $ Result x
compute3 :: Monad m => Int -> m (Result Int)
compute3 = return . compute
main :: IO()
main = do
let results = mapM compute [1..5]
print $ results
results2 <- mapM compute2 [1..5]
print $ sequence results2
results3 <- mapM compute3 [1..5]
print $ sequence results3
let results2' = runIdentity $ mapM compute2 [1..5]
print $ sequence results2'
Der Ausgang:
1
2
Failure
1
2
4
5
Failure
1
2
Failure
1
2
Failure
Vielen Dank für Ihre Antwort, Chi. Darf ich fragen, woher Sie wissen, dass die IO-Definition von mapM streng ist und dass die Rückkehr faul ist? – NioBium
@NioBium 'Failure >> = f = Fehler' verwirft das 'f': Es ist nicht notwendig, weiter auf der monadischen Kette fortzufahren. IO hat eine niedrigere Hebeldefinition, die nicht leicht geschrieben werden kann, aber - abgesehen von Ausnahmen - "action" = f wird immer "f" aufrufen, da man erwartet, dass z. "action >> print 4" wird schließlich 4 drucken, egal was "action" tut (Ausnahme von IO-Ausnahmen und Nicht-Beendigung). – chi
Rechts. Danke noch einmal! – NioBium