À partir de ce fil (de Contrôle.Monade.Suite plaisir, 2005), Tomasz Zielonka introduit une fonction (a commenté dans un style clair et agréable manière de Thomas Jäger). Tomasz prend l'argument (une fonction) d'un callCC corps et la retourne pour une utilisation ultérieure avec les deux définitions suivantes:
import Control.Monad.Cont
...
getCC :: MonadCont m => m (m a)
getCC = callCC (\c -> let x = c x in return x)
getCC' :: MonadCont m => a -> m (a, a -> m b)
getCC' x0 = callCC (\c -> let f x = c (x, f) in return (x0, f))
Ceux-ci sont également mentionnés dans Haskellwiki. En les utilisant, vous pouvez ressembler à goto sémantique en haskell qui a l'air vraiment cool:
import Control.Monad.Cont
getCC' :: MonadCont m => a -> m (a, a -> m b)
getCC' x0 = callCC (\c -> let f x = c (x, f) in return (x0, f))
main :: IO ()
main = (`runContT` return) $ do
(x, loopBack) <- getCC' 0
lift (print x)
when (x < 10) (loopBack (x + 1))
lift (putStrLn "finish")
Ce imprime les numéros de 0 à 10.
Voici le point intéressant. J'ai utilisé cette collaboration avec l'Écrivain Monade résoudre un certain problème. Mon code ressemble à ce qui suit:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
import Control.Monad.Cont
import Control.Monad.Writer
getCC :: MonadCont m => m (m a)
getCC = callCC (\c -> let x = c x in return x)
getCC' :: MonadCont m => a -> m (a, a -> m b)
getCC' x0 = callCC (\c -> let f x = c (x, f) in return (x0, f))
-- a simple monad transformer stack involving MonadCont and MonadWriter
type APP= WriterT [String] (ContT () IO)
runAPP :: APP a -> IO ()
runAPP a= runContT (runWriterT a) process
where process (_,w)= do
putStrLn $ unlines w
return ()
driver :: Int -> APP ()
driver k = do
tell [ "The quick brown fox ..." ]
(x,loop) <- getCC' 0
collect x
when (x<k) $ loop (x+1)
collect :: Int -> APP ()
collect n= tell [ (show n) ]
main :: IO ()
main = do
runAPP $ driver 4
Lorsque vous compilez et exécutez ce code, le résultat est:
The quick brown fox ...
4
Les chiffres de zéro à trois en cas d'ingestion de quelque part dans l'obscurité profonde de cet exemple.
Maintenant, dans le "Monde Réel Haskell" O'Sullivan, Goerzen et Stewart unis
"L'empilage monade transformateurs est analogue à la composition de fonctions. Si on change l'ordre dans lequel on applique des fonctions et ensuite obtenir des résultats différents, nous ne serons pas surpris. C'est donc avec une monade transformateurs, trop." (Real World Haskell, 2008, P. 442)
Je suis venu avec l'idée d'intervertir les transformateurs ci-dessus:
--replace in the above example
type APP= ContT () (WriterT [String] IO)
...
runAPP a = do
(_,w) <- runWriterT $ runContT a (return . const ())
putStrLn $ unlines w
Toutefois, cela ne compile pas car il n'existe pas de définition d'instance pour MonadWriter dans le Contrôle.Monade.Suite (c'est pourquoi j'ai récemment demandé à cette question.)
Nous avons ajouter une instance laissant écouter et passer undefined:
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell = lift . tell
listen = undefined
pass = undefined
Ajouter ces lignes, le compiler et l'exécuter. Tous les numéros sont imprimés.
Ce qui s'est passé dans l'exemple précédent?