haskellmonadscontinuationsfree-monadhaskell-pipes

Is there a standard abstraction for this request-response type?


I have the following type:

data S req rsp = Done rsp | Next req (rsp -> S req rsp)

The idea is to use it as a pure representation for network communication, i.e:

... Next GetUser $ \uid -> Next (Login uid) $ \success -> Done success

Which would then be evaluated by some impure function eval.

Now, what is this (if anything?) It's not a monad, neither an arrow, as far as I can see. It seems to be something between a stream/pipe/automaton/fsm and the continuation monad. This makes me think that there might be a better representation for this type of thing, but what?


Solution

  • It's Free Monad. The idea is that you have a description of instructions for which you can have multiple interpreters like your eval function. Free Monad abstracts over the pattern that this task has. For details I recommend this great post.

    To adapt your type to Free we can do the following:

    {-# LANGUAGE DeriveFunctor #-}
    
    import Control.Monad.Free
    
    data Instruction req rsp next =
      Respond rsp |
      Interact req (rsp -> next)
      deriving (Functor)
    
    type S req rsp =
      Free (Instruction req rsp)
    
    respond :: rsp -> S req rsp ()
    respond rsp =
      liftF (Respond rsp)
    
    interact :: req -> S req rsp rsp
    interact req =
      liftF (Interact req id)
    

    Now, thanks to Free, S req rsp is a monad, which means that you can now compose your respond and interact functions using Monad API.

    There's more to it. The respond and interact functions could be generated using Template Haskell with the following extra code:

    {-# LANGUAGE TemplateHaskell #-}
    
    import Control.Monad.Free.TH
    
    makeFree ''Instruction