A confusing title for a confusing question! I understand a) monads, b) the IO monad, c) the Cont monad (Control.Monad.Cont), and d) the ContT continuation transformer monad. (And I vaguely understand monad transformers in general -- though not enough to answer this question.) I understand how to write a program where all the functions are in the Cont monad (Cont r a
), and I understand how to write a program where all the functions are in the combined Cont/IO monad (ContT r IO a
).
But I'm wondering how I might write a program where some functions are in a combined Cont/IO monad (ContT r IO a
) and other functions are just in the Cont monad (Cont r a
). Basically, I want to write the whole program in continuation style, but only use the IO monad where necessary (much like in "regular" Haskell code, I only use the IO monad where necessary).
For example consider these two functions, in non-continuation style:
foo :: Int -> IO Int
foo n = do
let x = n + 1
print x
return $ bar x
bar :: Int -> Int
bar m = m * 2
Note that foo
requires IO but bar
is pure. Now I figured out how to write this code fully using the continuation monad, but I needed to thread IO through bar
as well:
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
I do want all my code in continuation style, but I don't want to have to use the IO monad on functions that don't require it. Basically, I would like to define bar
like this:
bar :: Int -> Cont r Int
bar m = return $ m * 2
Unfortunately, I can't find a way to call a Cont r a
monad function (bar
) from inside a ContT r IO a
monad function (foo
). Is there any way to "lift" a non-transformed monad into a transformed one? i.e., how can I change the line "bar x
" in foo
so that it can correctly call bar :: Int -> Cont r Int
?