{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Effect.Labelled
( runLabelled
, Labelled(Labelled)
, LabelledMember(..)
, HasLabelled
, sendLabelled
, runUnderLabel
, UnderLabel(UnderLabel)
, module Control.Algebra
) where
import Control.Algebra
import Control.Applicative (Alternative)
import Control.Effect.Sum (reassociateSumL)
import Control.Monad (MonadPlus)
import Control.Monad.Fail as Fail
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Data.Functor.Identity
import Data.Kind (Type)
newtype Labelled (label :: k) (sub :: (Type -> Type) -> (Type -> Type)) m a = Labelled (sub m a)
deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadIO, MonadPlus, MonadTrans)
runLabelled :: forall label sub m a . Labelled label sub m a -> sub m a
runLabelled (Labelled l) = l
{-# INLINE runLabelled #-}
instance Algebra (eff :+: sig) (sub m) => Algebra (Labelled label eff :+: sig) (Labelled label sub m) where
alg hdl = \case
L eff -> Labelled . alg (runLabelled . hdl) (L (runLabelled eff))
R sig -> Labelled . alg (runLabelled . hdl) (R sig)
{-# INLINE alg #-}
class LabelledMember label (sub :: (Type -> Type) -> (Type -> Type)) sup | label sup -> sub where
injLabelled :: Labelled label sub m a -> sup m a
instance LabelledMember label t (Labelled label t) where
injLabelled = id
{-# INLINE injLabelled #-}
instance {-# OVERLAPPABLE #-}
LabelledMember label t (l1 :+: l2 :+: r)
=> LabelledMember label t ((l1 :+: l2) :+: r) where
injLabelled = reassociateSumL . injLabelled
{-# INLINE injLabelled #-}
instance {-# OVERLAPPABLE #-}
LabelledMember label l (Labelled label l :+: r) where
injLabelled = L
{-# INLINE injLabelled #-}
instance {-# OVERLAPPABLE #-}
LabelledMember label l r
=> LabelledMember label l (l' :+: r) where
injLabelled = R . injLabelled
{-# INLINE injLabelled #-}
type HasLabelled label eff sig m = (LabelledMember label eff sig, Algebra sig m)
sendLabelled :: forall label eff sig m a . HasLabelled label eff sig m => eff m a -> m a
sendLabelled op = runIdentity <$> alg (fmap Identity . runIdentity) (injLabelled @label (Labelled op)) (Identity ())
{-# INLINABLE sendLabelled #-}
newtype UnderLabel (label :: k) (sub :: (Type -> Type) -> (Type -> Type)) (m :: Type -> Type) a = UnderLabel (m a)
deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadIO, MonadPlus)
runUnderLabel :: forall label sub m a . UnderLabel label sub m a -> m a
runUnderLabel (UnderLabel l) = l
{-# INLINE runUnderLabel #-}
instance MonadTrans (UnderLabel sub label) where
lift = UnderLabel
{-# INLINE lift #-}
instance (LabelledMember label sub sig, Algebra sig m) => Algebra (sub :+: sig) (UnderLabel label sub m) where
alg hdl = \case
L sub -> UnderLabel . alg (runUnderLabel . hdl) (injLabelled @label (Labelled sub))
R sig -> UnderLabel . alg (runUnderLabel . hdl) sig
{-# INLINE alg #-}