Monads may be construed as forms of containers:
I am wondering how continuations are interpreted in this view as forms of packages / containers, in a meaningful fashion. Thanks!
I like to think of continuations as programs with holes in them. I think I originally gleaned this insight from Tekmo's blog.
Check out this little continuation:
import Control.Monad.Trans.Cont
program :: ContT () IO Char
program = ContT $ \doThing -> do
c <- getChar
doThing c
It's a program that's 'missing a piece' - namely, what to do with the Char
retrieved from getChar
. We can run it by filling the missing piece with something like putChar
; evaluating the continuation via runContT program putChar
will get a character and then print it to stdout.
If you're comfortable with representing programs by abstract syntax trees the container analogy might be intuitive.
To make it clearer, you can build up a little AST containing a DoThing
term that represents a hole that needs to be filled:
{-# LANGUAGE DeriveFunctor #-}
import Control.Monad.Free
data ExprF a =
GetChar (Char -> a)
| DoThing Char a
deriving Functor
type Expr = Free ExprF
getChar' :: Expr Char
getChar' = liftF (GetChar id)
doThing' :: Char -> Expr ()
doThing' c = liftF (DoThing c ())
program' :: Expr ()
program' = do
c <- getChar'
doThing' c
program'
is hopefully more clearly a container; to run it we need to process the AST in a similar fashion as we would any other recursive container:
eval :: Expr () -> (Char -> IO ()) -> IO ()
eval prog f = iterM alg prog where
alg (GetChar k) = getChar >>= k
alg (DoThing c k) = f c >> k
Evaluating program'
via eval program' putChar
is analogous to running program
via runContT program putChar
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With