{-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE CPP #-} {-# LANGUAGE Safe #-} -- | Operational Monad (<https://wiki.haskell.org/Operational>) implemented with -- extensible effects. module Control.Eff.Operational ( Program (..) , singleton , runProgram -- * Usage -- $usage ) where import Control.Eff import Data.OpenUnion -- | Lift values to an effect. -- You can think this is a generalization of @Lift@. data Program instr v = forall a. Program (instr a) (a -> v) -- | Lift a value to a monad. singleton :: (Member (Program instr) r) => instr a -> Eff r a singleton instr = send $ (Program instr) id -- | Convert values using given interpreter to effects. runProgram :: (forall x. f x -> Eff r x) -> Eff (Program f ': r) a -> Eff r a runProgram advent = handle_relay return h where h (Program instr v) k = advent instr >>= k . v -- $usage -- -- See "Control.Eff.Operational.Example" for an example of defining data using -- GADTs and implementing interpreters from the data to effects. -- -- To use the interpreter, see below or consult the tests. -- -- @ --main :: IO () --main = do -- let comp = 'runProgram' adventPure prog -- putStrLn . fst . 'run' . 'runMonoidWriter' $ 'evalState' comp [\"foo\",\"bar\"] -- 'runLift' $ 'runProgram' adventIO prog -- @