{-# LANGUAGE DefaultSignatures, DeriveFunctor, FlexibleInstances, FunctionalDependencies, RankNTypes, UndecidableInstances #-}
module Control.Effect.Carrier
( HFunctor(..)
, Effect(..)
, Carrier(..)
, handlePure
, handleCoercible
, handleReader
, handleState
, handleEither
, handleTraversable
, interpret
) where
import Control.Monad (join)
import Data.Coerce
class HFunctor h where
fmap' :: (a -> b) -> (h m a -> h m b)
default fmap' :: Functor (h m) => (a -> b) -> (h m a -> h m b)
fmap' = fmap
{-# INLINE fmap' #-}
hmap :: (forall x . m x -> n x) -> (h m a -> h n a)
class HFunctor sig => Effect sig where
handle :: Functor f
=> f ()
-> (forall x . f (m x) -> n (f x))
-> sig m (m a)
-> sig n (n (f a))
class (HFunctor sig, Monad m) => Carrier sig m | m -> sig where
eff :: sig m (m a) -> m a
ret :: a -> m a
ret = pure
{-# DEPRECATED ret "Use 'pure' instead; 'ret' is a historical alias and will be removed in future versions" #-}
handlePure :: HFunctor sig => (forall x . f x -> g x) -> sig f (f a) -> sig g (g a)
handlePure handler = hmap handler . fmap' handler
{-# INLINE handlePure #-}
handleCoercible :: (HFunctor sig, Coercible f g) => sig f (f a) -> sig g (g a)
handleCoercible = handlePure coerce
{-# INLINE handleCoercible #-}
{-# DEPRECATED handleReader, handleState, handleEither, handleTraversable
"Compose carrier types from other carriers and define 'eff' with handleCoercible instead" #-}
handleReader :: HFunctor sig => r -> (forall x . f x -> r -> g x) -> sig f (f a) -> sig g (g a)
handleReader r run = handlePure (flip run r)
{-# INLINE handleReader #-}
handleState :: Effect sig => s -> (forall x . f x -> s -> g (s, x)) -> sig f (f a) -> sig g (g (s, a))
handleState s run = handle (s, ()) (uncurry (flip run))
{-# INLINE handleState #-}
handleEither :: (Carrier sig g, Effect sig) => (forall x . f x -> g (Either e x)) -> sig f (f a) -> sig g (g (Either e a))
handleEither run = handle (Right ()) (either (pure . Left) run)
{-# INLINE handleEither #-}
handleTraversable :: (Effect sig, Applicative g, Monad m, Traversable m) => (forall x . f x -> g (m x)) -> sig f (f a) -> sig g (g (m a))
handleTraversable run = handle (pure ()) (fmap join . traverse run)
{-# INLINE handleTraversable #-}
interpret :: carrier a -> carrier a
interpret = id
{-# DEPRECATED interpret "Not necessary with monadic carriers; remove or replace with 'id'." #-}