{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Carrier.Interpret
(
runInterpret
, runInterpretState
, InterpretC(InterpretC)
, Reifies
, Interpreter
, Algebra
, Has
, run
) where
import Control.Algebra
import Control.Applicative (Alternative)
import Control.Carrier.State.Strict
import Control.Monad (MonadPlus)
import 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 Data.Kind (Type)
import Unsafe.Coerce (unsafeCoerce)
newtype Interpreter sig m = Interpreter
{ runInterpreter :: forall ctx n s x . Functor ctx => Handler ctx n (InterpretC s sig m) -> sig n x -> ctx () -> InterpretC s sig m (ctx 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
:: (forall ctx n x . Functor ctx => Handler ctx n m -> eff n x -> ctx () -> m (ctx x))
-> (forall s . Reifies s (Interpreter eff m) => InterpretC s eff m a)
-> m a
runInterpret f m = reify (Interpreter (\ hdl sig -> InterpretC . f (runInterpretC . hdl) sig)) (go m) where
go :: InterpretC s eff m x -> Const (m x) s
go (InterpretC m) = Const m
{-# INLINE runInterpret #-}
runInterpretState
:: (forall ctx n x . Functor ctx => Handler ctx n (StateC s m) -> eff n x -> s -> ctx () -> m (s, ctx x))
-> s
-> (forall t . Reifies t (Interpreter eff (StateC s m)) => InterpretC t eff (StateC s m) a)
-> m (s, a)
runInterpretState handler state m
= runState state
$ runInterpret (\ hdl sig ctx -> StateC (flip (handler hdl sig) ctx)) m
{-# INLINE runInterpretState #-}
newtype InterpretC s (sig :: (Type -> Type) -> (Type -> Type)) m a = InterpretC { runInterpretC :: m a }
deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus)
instance MonadTrans (InterpretC s sig) where
lift = InterpretC
{-# INLINE lift #-}
instance (Reifies s (Interpreter eff m), Algebra sig m) => Algebra (eff :+: sig) (InterpretC s eff m) where
alg hdl = \case
L eff -> runInterpreter (getConst (reflect @s)) hdl eff
R other -> InterpretC . alg (runInterpretC . hdl) other
{-# INLINE alg #-}