{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs #-} {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | A simpler, non-transformer version of this package's -- "Control.Monad.Operational"\'s 'Program' type, using 'Free' -- directly. module Control.Monad.Operational.Simple ( module Control.Operational.Class , Program(..) , interpret , fromProgram , ProgramView(..) , view ) where import Control.Applicative import Control.Monad.Free import Control.Operational.Class import Control.Operational.Instruction import Data.Functor.Coyoneda newtype Program instr a = Program { -- | Intepret the program as a 'Free' monad. toFree :: Free (Coyoneda instr) a } deriving (Functor, Applicative, Monad) instance Operational instr (Program instr) where singleton = Program . liftF . liftInstr -- | Interpret a 'Program' by translating each instruction to a -- 'Monad' action. Does not use 'view'. interpret :: forall m instr a. (Functor m, Monad m) => (forall x. instr x -> m x) -> Program instr a -> m a interpret evalI = retract . hoistFree (liftEvalI evalI) . toFree -- | Lift a 'Program' to any 'Operational' instance at least as -- powerful as 'Monad'. fromProgram :: (Operational instr m, Functor m, Monad m) => Program instr a -> m a fromProgram = interpret singleton data ProgramView instr a where Return :: a -> ProgramView instr a (:>>=) :: instr a -> (a -> Program instr b) -> ProgramView instr b view :: Program instr a -> ProgramView instr a view = eval . toFree where eval (Pure a) = Return a eval (Free (Coyoneda f i)) = i :>>= (Program . f)