Un titre prêtant à confusion pour une question déroutante! Je comprends a) les monades, b) la monade IO, c) la monade Cont (Control.Monad.Cont), et d) la monade de transformateur suite ContT. (Et je comprends vaguement les transformateurs Monad en général - mais pas assez pour répondre à cette question.) Je comprends comment écrire un programme où toutes les fonctions sont dans la monade Cont (Cont r a
), et je comprends comment écrire un programme où tous les fonctions sont dans la monade Cont/IO combinée (ContT r IO a
).Echapper de la monade IO à l'intérieur de la monade Continuation
Mais je me demande comment je pourrais écrire un programme où certaines fonctions sont dans un Cont/monade IO combiné (ContT r IO a
) et autres fonctions ne sont que dans la suite monade (Cont r a
). Fondamentalement, je veux écrire l'ensemble du programme dans le style de continuation, mais seulement utiliser la monade IO si nécessaire (un peu comme dans le code Haskell "normal", je n'utilise que la monade IO si nécessaire).
Par exemple, considérons ces deux fonctions, dans un style non-continuation:
foo :: Int -> IO Int
foo n = do
let x = n + 1
print x
return $ bar x
bar :: Int -> Int
bar m = m * 2
Notez que foo
EXIGE IO mais bar
est pur. Maintenant, je compris comment écrire ce code en utilisant pleinement la poursuite monade, mais je devais enfiler IO par bar
ainsi:
foo :: Int -> ContT r IO Int
foo n = do
let x = n + 1
liftIO $ print x
bar x
bar :: Int -> ContT r IO Int
bar m = return $ m * 2
Je ne veux tout mon code dans le style de continuation, mais je n » t souhaitez utiliser la monade d'E/S sur les fonctions qui ne l'exigent pas. Au fond, je voudrais définir bar
comme ceci:
bar :: Int -> Cont r Int
bar m = return $ m * 2
Malheureusement, je ne peux pas trouver un moyen d'appeler une fonction Cont r a
monade (bar
) à l'intérieur d'une fonction ContT r IO a
monade (foo
). Existe-t-il un moyen de "soulever" une monade non transformée en une monade transformée? c'est-à-dire, comment puis-je changer la ligne "bar x
" en foo
afin qu'il puisse appeler correctement bar :: Int -> Cont r Int
?
Merci. Ça marche. J'ai aussi trouvé ma propre solution, qui me donnait exactement ce que je voulais (je n'avais pas à changer 'Bar'):' liftCont :: Cont (m) a -> ContT r m a'; 'liftCont c = ContT $ runCont c'. Ma solution décompresse le 'Cont' et construit un' ContT'. Je pense que votre solution est plus agréable car elle est polymorphe et ne nécessite pas de manipulation réelle des structures de données, alors cochez pour vous. Mais je vais poster le mien comme une autre réponse, car c'est utile au cas où vous ne pouvez pas modifier 'bar'. Aussi +1 pour expliquer pourquoi il serait impossible d'utiliser IO dans 'bar'. – mgiuca