{-# LANGUAGE FlexibleContexts, FlexibleInstances, FunctionalDependencies, GeneralizedNewtypeDeriving, KindSignatures, RankNTypes, ScopedTypeVariables, TypeApplications, TypeOperators, UndecidableInstances #-}
module Control.Carrier.Interpret
(
runInterpret
, runInterpretState
, InterpretC(..)
, Reifies
, Handler
, Algebra
, Has
, run
) where
import Control.Algebra
import Control.Applicative (Alternative(..))
import Control.Carrier.State.Strict
import Control.Monad (MonadPlus(..))
import qualified Control.Monad.Fail as Fail
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Data.Functor.Const (Const(..))
import Unsafe.Coerce (unsafeCoerce)
newtype Handler sig m = Handler
{ runHandler :: forall s x . sig (InterpretC s sig m) x -> InterpretC s sig m x }
class Reifies s a | s -> a where
reflect :: Const a s
data Skolem
newtype Magic a r = Magic (Reifies Skolem a => Const r Skolem)
reify :: a -> (forall s . Reifies s a => Const r s) -> r
reify a k = unsafeCoerce (Magic k) a
runInterpret
:: (HFunctor eff, Monad m)
=> (forall x . eff m x -> m x)
-> (forall s . Reifies s (Handler eff m) => InterpretC s eff m a)
-> m a
runInterpret f m = reify (Handler (InterpretC . f . handleCoercible)) (go m) where
go :: InterpretC s eff m x -> Const (m x) s
go (InterpretC m) = Const m
runInterpretState
:: (HFunctor eff, Monad m)
=> (forall x . s -> eff (StateC s m) x -> m (s, x))
-> s
-> (forall t . Reifies t (Handler eff (StateC s m)) => InterpretC t eff (StateC s m) a)
-> m (s, a)
runInterpretState handler state m
= runState state
$ runInterpret (\e -> StateC (\s -> handler s e)) m
newtype InterpretC s (sig :: (* -> *) -> * -> *) m a = InterpretC (m a)
deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus)
instance MonadTrans (InterpretC s sig) where
lift = InterpretC
instance (HFunctor eff, HFunctor sig, Reifies s (Handler eff m), Monad m, Algebra sig m) => Algebra (eff :+: sig) (InterpretC s eff m) where
alg (L eff) = runHandler (getConst (reflect @s)) eff
alg (R other) = InterpretC (alg (handleCoercible other))