# Thinking of Monads as imperative languages Haskell provides `do` notation, which is syntactic sugar to facilitate imperative programming. The `Monad` of a `do` block specifies the *imperative language*, which is typically equipped with *actions* (you might call them verbs of the language). ```haskell ioExample :: IO () ioExample = do putStr "What is your name? " -- an action which prints to the console name <- getLine -- an action which retrieves a line from the console putStrLn "Hello, " ++ name stateExample :: State Int () stateExample = do x <- get -- an action which retrieves the current state put (x + 1) -- an action which overrides the current state ``` These examples which I have defined are *actions* themselves. In other words, I have created new verbs in their respective languages, which have a meaning defined as a combination of other actions. We can invoke these actions within a `do` block of the appropriate language. ```haskell invokeIOExample :: IO () invokeIOExample = do ioExample otherIOStuff invokeStateExample :: State Int () stateExample otherStateStuff ``` Monad laws represent the well-foundedness of refactoring. When definitions are inlined or factored out, the monad laws guarnatee that the meaning stays the same. I won't illustrate this, but it's important to think about if you haven't already. Monad transformers, then, are language enhancers. They add additional actions to an underlying language. You might call them *language transformers*. # The Pause transformer Today we are going to write a monad transformer. This transformer will augment the underlying language with one additional action: `pause`. This way, we will be able to build (for example) an IO action which can run for a while, and then pause itself when it reaches a checkpoint. At that point, it will produce a new action which can be run to continue where it left off, until the next pause point. Let's start off simple. ```haskell data Pause m = Run (m (Pause m)) | Done pauseExample1 :: Pause IO pauseExample1 = Run $ do putStrLn "Let's begin" putStrLn "Step 1" return $ Run $ do putStrLn "Step 2" return $ Run $ do putStrLn "Step 3" putStrLn "Yay, we're done!" return Done ``` Fairly simple stuff, though currently a bit crufty. We would like to be able to step these actions, or perhaps we would like to ignore the pauses and run them to completion. ```active haskell data Pause m = Run (m (Pause m)) | Done pauseExample1 :: Pause IO pauseExample1 = Run $ do putStrLn "Let's begin" putStrLn "Step 1" return $ Run $ do putStrLn "Step 2" return $ Run $ do putStrLn "Step 3" putStrLn "Yay, we're done!" return Done -- show Try implementing these runN :: Monad m => Int -> Pause m -> m (Pause m) runN = undefined fullRun :: Monad m => Pause m -> m () fullRun = undefined -- show Check the result main = do rest <- runN 2 pauseExample1 putStrLn "=== should print through step 2 ===" Done <- runN 1 rest -- remember, IO Foo is just a recipe for Foo, not a Foo itself -- so we can run that recipe again fullRun rest fullRun pauseExample1 ``` @@@ spoilers ```haskell runN :: Monad m => Int -> Pause m -> m (Pause m) runN 0 p = return p runN _ Done = return Done runN n (Run m) | n < 0 = fail "Invalid argument to runN" -- ewww I just used fail. | otherwise = m >>= runN (n - 1) fullRun :: Monad m => Pause m -> m () fullRun Done = return () fullRun (Run m) = m >>= fullRun ``` @@@ Nifty. # Making Pause a real transformer We accomplished what we wanted with the earlier code, but the way we had to write `pauseExample1` was ugly. We want to create a "real" monad transformer, with a `pause` action. For this example, it is as simple as adding a result to the `Done` constructor. ```active haskell -- show Given this definition... import Control.Monad import Control.Monad.Trans.Class data PauseT m r = RunT (m (PauseT m r)) | DoneT r -- show implement these instance (Monad m) => Monad (PauseT m) where -- return :: Monad m => a -> PauseT m a return a = undefined -- (>>=) :: Monad m => PauseT m a -> (a -> PauseT m b) -> PauseT m b DoneT r >>= f = undefined RunT m >>= f = undefined instance MonadTrans PauseT where -- lift :: Monad m => m a -> PauseT m a lift m = undefined pause :: Monad m => PauseT m () pause = undefined -- bonus exercise, implement joinP -- double bonus: without relying on PauseT's monad instance -- triple bonus: explain in English what joinP *means* for the Pause monad joinP :: Monad m => PauseT m (PauseT m a) -> PauseT m a joinP = undefined -- show ...and see if it compiles. main = putStrLn "it compiles" ``` UPDATE: Whoops, /r/haskell pointed out that there are problems with this representation of PauseT. Skip down below and see if you can figure out what's wrong. Then, please move on to Part 2 where we will build a better abstraction that obeys laws and works as you'd expect. @@@ sample implementation ```haskell -- UPDATE: This implementation disobeys MonadTrans laws, -- and pause isn't quite right. instance (Monad m) => Monad (PauseT m) where return a = DoneT a DoneT r >>= f = f r RunT m >>= f = RunT $ liftM (>>= f) m instance MonadTrans PauseT where lift m = RunT $ liftM DoneT m pause :: Monad m => PauseT m () pause = DoneT () ``` @@@ Great, now we can use `pause`, and `lift` anything else from the base language. ```active haskell --/show import Control.Monad import Control.Monad.Trans.Class data PauseT m r = RunT (m (PauseT m r)) | DoneT r instance (Monad m) => Monad (PauseT m) where return a = DoneT a DoneT r >>= f = f r RunT m >>= f = RunT $ liftM (>>= f) m instance MonadTrans PauseT where lift m = RunT $ liftM DoneT m pause :: Monad m => PauseT m () pause = DoneT () --show example2 :: PauseT IO () example2 = do lift $ putStrLn "Step 1" pause lift $ putStrLn "Step 2" pause lift $ putStrLn "Step 3" fullRunT :: PauseT IO r -> IO r fullRunT (DoneT r) = return r fullRunT (RunT m) = m >>= fullRunT runNT :: Int -> PauseT IO r -> IO (PauseT IO r) runNT 0 p = return p runNT _ d@DoneT{} = return d runNT n (RunT m) = m >>= runNT (n - 1) main = do fail "your turn" fail "Fill in this main method with your own experiments" ``` If you don't like all the `lift`ing, then try using a typeclass like `MonadIO`. Not always the best idea, but it's an option worth knowing about. I used the `IO` monad, because it is fairly easy to understand a prodecural idea like "pause" in those terms. What would PauseT *mean* if it were on top of the State monad? The List monad? Food for thought. # Enhancements `PauseT` adds a way for us to pause ourselves, waiting patiently for whoever is "in charge" to resume us. Who is this mysterious "in charge" person? What if we could communicate with her? Next time, we will learn about coroutines, and elaborate a simple interface for bidirectional communication. (Then we can implement `PauseT` in terms of this new abstraction, by setting the "to" and "from" fields to the trivial message, `()`.)