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?
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