Search code examples
haskellmonadscontinuations

Is this an appropriate use of ContT?


I'm working on a project that requires me to write a small interpreter. The instructions have a simple tree structure and one of the commands has the effect of halting execution. So in the example below, "baz" is never printed.

import Control.Monad.Cont

data Instruction = Print String | Halt | Block [Instruction]
    deriving (Eq, Show)

instructions =
  [ Print "foo"
  , Block
    [ Print "bar"
    , Halt
    ]
  , Print "baz"
  ]

main :: IO ()
main = runContT (callCC $ interpret instructions)
                (const $ pure ())

interpret []     k = pure ()
interpret (a:as) k = case a of
    Print str -> liftIO (putStrLn str) >> interpret as k
    Block ins -> interpret ins k       >> interpret as k
    Halt      -> k ()

This is the first time I've seen a potential use for ContT in one of my projects. I was wondering if this is an appropriate use of it or if there is a simpler solution I might be overlooking.


Solution

  • Yes, this looks to be precisely the sort of use case for which Control.Monad.Cont is appropriate.

    You are almost certainly aware of this, but for other readers, it's worth spelling out that if you'd written interpret so that it was a function from a list of instructions to an IO () like so:

    main :: IO ()
    main = interpret instructions
    
    interpret :: [Instruction] -> IO ()
    interpret []     = pure ()
    interpret (a:as) = case a of
        Print str -> putStrLn str >> interpret as
        Block ins -> interpret ins >> interpret as
        Halt      -> pure ()
    

    then foo bar and baz all would have printed. What you needed was an escape mechanism that would allow you to abort the entire computation and immediately return a value. This is precisely what callCC provides. Calling the named computation (k in your code) allows you to escape out of the whole computation, not just that level/layer.

    So good job, you've found precisely the appropriate use case for ContT here, I believe.