Skip to content

Instantly share code, notes, and snippets.

@joshcough
Created June 9, 2019 15:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshcough/5e649e08c794bbce3442f13d4bcd492b to your computer and use it in GitHub Desktop.
Save joshcough/5e649e08c794bbce3442f13d4bcd492b to your computer and use it in GitHub Desktop.
import Control.Monad.RWS.Lazy
data Action = Fail | Proceed
data Command = Command1 | Command2
newtype MyState = MyState Int
-- step function that might do some IO while processing Commands
-- such as going to the database before producing an Action and the next State
stepM :: Monad m => MyState -> Command -> m (Action, Maybe MyState)
stepM = undefined
-- single step in the interpreter, manages state propagation
stepRWST :: Monad m => Command -> RWST () [Action] (Maybe MyState) m (Maybe MyState)
stepRWST c = RWST $ \_ ms -> case ms of
Nothing -> return (Nothing, Nothing, [])
Just s -> do
(a, ms') <- stepM s c
return (ms', ms', [a])
-- generic driver of computation
interpretM' :: Monad m => [c] -> s -> (c -> RWST () [w] s m a) -> m ([a], s, [w])
interpretM' commands initState f = runRWST (traverse f commands) () initState
-- the actual interpreter
interpretM :: Monad m => [Command] -> MyState -> m [(Action, Maybe MyState)]
interpretM commands initState = do
(as, _, ws) <- interpretM' commands (Just initState) stepRWST
return $ zip ws as
-- an example of using the interpreter
testM :: Monad m => m [(Action, Maybe MyState)]
testM = interpretM [Command1, Command2] (MyState 42)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment