{-# LANGUAGE DefaultSignatures, EmptyCase, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, TypeOperators #-}
module Control.Effect.Class
( HFunctor(..)
, handleCoercible
, Effect(..)
, GHFunctor(..)
, GEffect(..)
) where
import Data.Coerce
import GHC.Generics
class HFunctor h where
hmap :: Functor m => (forall x . m x -> n x) -> (h m a -> h n a)
default hmap :: (Functor m, Generic1 (h m), Generic1 (h n), GHFunctor m n (Rep1 (h m)) (Rep1 (h n))) => (forall x . m x -> n x) -> (h m a -> h n a)
hmap f = to1 . ghmap f . from1
{-# INLINE hmap #-}
handleCoercible :: (HFunctor sig, Functor f, Coercible f g) => sig f a -> sig g a
handleCoercible = hmap coerce
{-# INLINE handleCoercible #-}
class HFunctor sig => Effect sig where
thread
:: (Functor ctx, Monad m)
=> ctx ()
-> (forall x . ctx (m x) -> n (ctx x))
-> sig m a
-> sig n (ctx a)
default thread
:: (Functor ctx, Monad m, Generic1 (sig m), Generic1 (sig n), GEffect m n (Rep1 (sig m)) (Rep1 (sig n)))
=> ctx ()
-> (forall x . ctx (m x) -> n (ctx x))
-> sig m a
-> sig n (ctx a)
thread ctx handler = to1 . gthread ctx handler . from1
{-# INLINE thread #-}
class GHFunctor m m' rep rep' where
ghmap :: Functor m => (forall x . m x -> m' x) -> (rep a -> rep' a)
instance GHFunctor m m' rep rep' => GHFunctor m m' (M1 i c rep) (M1 i c rep') where
ghmap f = M1 . ghmap f . unM1
{-# INLINE ghmap #-}
instance (GHFunctor m m' l l', GHFunctor m m' r r') => GHFunctor m m' (l :+: r) (l' :+: r') where
ghmap f (L1 l) = L1 (ghmap f l)
ghmap f (R1 r) = R1 (ghmap f r)
{-# INLINE ghmap #-}
instance (GHFunctor m m' l l', GHFunctor m m' r r') => GHFunctor m m' (l :*: r) (l' :*: r') where
ghmap f (l :*: r) = ghmap f l :*: ghmap f r
{-# INLINE ghmap #-}
instance GHFunctor m m' V1 V1 where
ghmap _ v = case v of {}
{-# INLINE ghmap #-}
instance GHFunctor m m' U1 U1 where
ghmap _ = id
{-# INLINE ghmap #-}
instance GHFunctor m m' (K1 R c) (K1 R c) where
ghmap _ = coerce
{-# INLINE ghmap #-}
instance GHFunctor m m' Par1 Par1 where
ghmap _ = coerce
{-# INLINE ghmap #-}
instance (Functor f, GHFunctor m m' g g') => GHFunctor m m' (f :.: g) (f :.: g') where
ghmap f = Comp1 . fmap (ghmap f) . unComp1
{-# INLINE ghmap #-}
instance GHFunctor m m' (Rec1 m) (Rec1 m') where
ghmap f = Rec1 . f . unRec1
{-# INLINE ghmap #-}
instance HFunctor f => GHFunctor m m' (Rec1 (f m)) (Rec1 (f m')) where
ghmap f = Rec1 . hmap f . unRec1
{-# INLINE ghmap #-}
class GEffect m m' rep rep' where
gthread
:: (Functor ctx, Monad m)
=> ctx ()
-> (forall x . ctx (m x) -> m' (ctx x))
-> rep a
-> rep' (ctx a)
instance GEffect m m' rep rep' => GEffect m m' (M1 i c rep) (M1 i c rep') where
gthread ctx handler = M1 . gthread ctx handler . unM1
{-# INLINE gthread #-}
instance (GEffect m m' l l', GEffect m m' r r') => GEffect m m' (l :+: r) (l' :+: r') where
gthread ctx handler (L1 l) = L1 (gthread ctx handler l)
gthread ctx handler (R1 r) = R1 (gthread ctx handler r)
{-# INLINE gthread #-}
instance (GEffect m m' l l', GEffect m m' r r') => GEffect m m' (l :*: r) (l' :*: r') where
gthread ctx handler (l :*: r) = gthread ctx handler l :*: gthread ctx handler r
{-# INLINE gthread #-}
instance GEffect m m' V1 V1 where
gthread _ _ v = case v of {}
{-# INLINE gthread #-}
instance GEffect m m' U1 U1 where
gthread _ _ = coerce
{-# INLINE gthread #-}
instance GEffect m m' (K1 R c) (K1 R c) where
gthread _ _ = coerce
{-# INLINE gthread #-}
instance GEffect m m' Par1 Par1 where
gthread ctx _ = Par1 . (<$ ctx) . unPar1
{-# INLINE gthread #-}
instance (Functor f, GEffect m m' g g') => GEffect m m' (f :.: g) (f :.: g') where
gthread ctx handler = Comp1 . fmap (gthread ctx handler) . unComp1
{-# INLINE gthread #-}
instance GEffect m m' (Rec1 m) (Rec1 m') where
gthread ctx handler = Rec1 . handler . (<$ ctx) . unRec1
{-# INLINE gthread #-}
instance Effect sig => GEffect m m' (Rec1 (sig m)) (Rec1 (sig m')) where
gthread ctx handler = Rec1 . thread ctx handler . unRec1
{-# INLINE gthread #-}