Haskell Language Free Monads Free monads split monadic computations into data structures and interpreters

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Extensions
> Step 2: And Like the video. BONUS: You can also share it!

Example

For instance, a computation involving commands to read and write from the prompt:

First we describe the "commands" of our computation as a Functor data type

{-# LANGUAGE DeriveFunctor #-}

data TeletypeF next
    = PrintLine String next
    | ReadLine (String -> next)
    deriving Functor

Then we use Free to create the "Free Monad over TeletypeF" and build some basic operations.

import Control.Monad.Free (Free, liftF, iterM)

type Teletype = Free TeletypeF

printLine :: String -> Teletype ()
printLine str = liftF (PrintLine str ())

readLine :: Teletype String
readLine = liftF (ReadLine id)

Since Free f is a Monad whenever f is a Functor, we can use the standard Monad combinators (including do notation) to build Teletype computations.

import Control.Monad -- we can use the standard combinators

echo :: Teletype ()
echo = readLine >>= printLine

mockingbird :: Teletype a
mockingbird = forever echo

Finally, we write an "interpreter" turning Teletype a values into something we know how to work with like IO a

interpretTeletype :: Teletype a -> IO a
interpretTeletype = foldFree run where
  run :: TeletypeF a -> IO a
  run (PrintLine str x) = putStrLn *> return x
  run (ReadLine f) = fmap f getLine

Which we can use to "run" the Teletype a computation in IO

> interpretTeletype mockingbird
hello
hello
goodbye
goodbye
this will go on forever
this will go on forever


Got any Haskell Language Question?