Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 415
Bryan Avatar asked Jul 03 '17 03:07

Bryan


People also ask

What is use content?

Content is the information contained within communication media. This includes internet, cinema, television, radio, audio CDs, books, magazines, physical art, and live event content. It's directed at an end-user or audience in the sectors of publishing, art, and communication.

What are the 3 types of content?

The best way to look at the kind of content you're using across your digital landscape, including social media and email marketing, as well as social media and your blog, is to divide it into three types. They are: Creation, Curation, and Creative Curation.

Why do we use content?

Creating content helps your business build a relationship with your audience. You can answer their questions and interact with customers. When you create value without taking anything in return, your audience is more likely to trust your advice and recommendations.


1 Answers

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.

like image 138
liminalisht Avatar answered Oct 11 '22 12:10

liminalisht