- haskell monads continuations
- Updated Wed, 24 Aug 2022 04:14:02 GMT

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`

?

This is where Control.Monad.Class comes in. Make `bar`

polymorphic in what monad it can work in:

```
bar :: MonadCont m => Int -> m Int
bar m = return $ m * 2
```

Note that the instances list at the bottom of the page shows that the instances of `MonadCont`

known at the time the docs were generated include both `Cont r`

and `Monad m => ContT r m`

. Additionally, the `MonadCont`

class is what defines the `callCC`

function, which is what is necessary to use the continuation features. This means you can use the full expressiveness of continuations within `bar`

, even though this example does not.

In this way, you write functions that provably can't use IO, because they don't have a `MonadIO`

constraint, nor does their type explicitly mention `IO`

. But they are polymorphic in which monad they work within, such that they can be called trivially from contexts that do include IO.

- +1 – Thanks. That works. I also found my own solution, which gave me exactly what I wanted (I didn't have to change
`Bar`

):`liftCont :: Cont (m r) a -> ContT r m a`

;`liftCont c = ContT $ runCont c`

. My solution unpacks the`Cont`

and constructs a`ContT`

. I think your solution is nicer because it's polymorphic and doesn't require actual manipulation of data structures, so tick for you. But I'll post mine as another answer, since it's helpful in case you can't modify`bar`

. Also +1 for explanation of why it would be impossible to use IO in`bar`

. — Jul 06, 2011 at 13:54

External links referenced by this document: