{-# LANGUAGE CPP #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE GADTs #-}
#if __GLASGOW_HASKELL__ >= 707
{-# LANGUAGE DeriveDataTypeable #-}
#endif
{-# OPTIONS_GHC -Wall #-}
module Control.Applicative.Trans.Free
(
ApT(..)
, ApF(..)
, liftApT
, liftApO
, runApT
, runApF
, runApT_
, hoistApT
, hoistApF
, transApT
, transApF
, Ap
, runAp
, runAp_
, retractAp
, Alt
, runAlt
) where
import Control.Applicative
import Data.Functor.Apply
import Data.Functor.Identity
import Data.Typeable
import Data.Monoid
import qualified Data.Foldable as F
data ApF f g a where
Pure :: a -> ApF f g a
Ap :: f a -> ApT f g (a -> b) -> ApF f g b
#if __GLASGOW_HASKELL__ >= 707
deriving Typeable
#endif
newtype ApT f g a = ApT { getApT :: g (ApF f g a) }
#if __GLASGOW_HASKELL__ >= 707
deriving Typeable
#endif
instance Functor g => Functor (ApF f g) where
fmap f (Pure a) = Pure (f a)
fmap f (Ap x g) = x `Ap` fmap (f .) g
instance Functor g => Functor (ApT f g) where
fmap f (ApT g) = ApT (fmap f <$> g)
instance Applicative g => Applicative (ApF f g) where
pure = Pure
{-# INLINE pure #-}
Pure f <*> y = fmap f y
y <*> Pure a = fmap ($ a) y
Ap a f <*> b = a `Ap` (flip <$> f <*> ApT (pure b))
{-# INLINE (<*>) #-}
instance Applicative g => Applicative (ApT f g) where
pure = ApT . pure . pure
{-# INLINE pure #-}
ApT xs <*> ApT ys = ApT ((<*>) <$> xs <*> ys)
{-# INLINE (<*>) #-}
instance Applicative g => Apply (ApF f g) where
(<.>) = (<*>)
{-# INLINE (<.>) #-}
instance Applicative g => Apply (ApT f g) where
(<.>) = (<*>)
{-# INLINE (<.>) #-}
instance Alternative g => Alternative (ApT f g) where
empty = ApT empty
{-# INLINE empty #-}
ApT g <|> ApT h = ApT (g <|> h)
{-# INLINE (<|>) #-}
liftApT :: Applicative g => f a -> ApT f g a
liftApT x = ApT (pure (Ap x (pure id)))
liftApO :: Functor g => g a -> ApT f g a
liftApO g = ApT (Pure <$> g)
runApF :: (Applicative h, Functor g) => (forall a. f a -> h a) -> (forall a. g (h a) -> h a) -> ApF f g b -> h b
runApF _ _ (Pure x) = pure x
runApF f g (Ap x y) = f x <**> runApT f g y
runApT :: (Applicative h, Functor g) => (forall a. f a -> h a) -> (forall a. g (h a) -> h a) -> ApT f g b -> h b
runApT f g (ApT a) = g (runApF f g <$> a)
runApT_ :: (Functor g, Monoid m) => (forall a. f a -> m) -> (g m -> m) -> ApT f g b -> m
runApT_ f g = getConst . runApT (Const . f) (Const . g . fmap getConst)
hoistApF :: Functor g => (forall a. f a -> f' a) -> ApF f g b -> ApF f' g b
hoistApF _ (Pure x) = Pure x
hoistApF f (Ap x y) = f x `Ap` hoistApT f y
hoistApT :: Functor g => (forall a. f a -> f' a) -> ApT f g b -> ApT f' g b
hoistApT f (ApT g) = ApT (hoistApF f <$> g)
transApF :: Functor g => (forall a. g a -> g' a) -> ApF f g b -> ApF f g' b
transApF _ (Pure x) = Pure x
transApF f (Ap x y) = x `Ap` transApT f y
transApT :: Functor g => (forall a. g a -> g' a) -> ApT f g b -> ApT f g' b
transApT f (ApT g) = ApT $ f (transApF f <$> g)
type Ap f = ApT f Identity
runAp :: Applicative g => (forall x. f x -> g x) -> Ap f a -> g a
runAp f = runApT f runIdentity
runAp_ :: Monoid m => (forall x. f x -> m) -> Ap f a -> m
runAp_ f = runApT_ f runIdentity
retractAp :: Applicative f => Ap f a -> f a
retractAp = runAp id
type Alt f = ApT f []
runAlt :: (Alternative g, F.Foldable t) => (forall x. f x -> g x) -> ApT f t a -> g a
runAlt f (ApT xs) = F.foldr (\x acc -> h x <|> acc) empty xs
where
h (Pure x) = pure x
h (Ap x g) = f x <**> runAlt f g
#if __GLASGOW_HASKELL__ < 707
instance (Typeable1 f, Typeable1 g) => Typeable1 (ApT f g) where
typeOf1 t = mkTyConApp apTTyCon [typeOf1 (f t)] where
f :: ApT f g a -> g (f a)
f = undefined
instance (Typeable1 f, Typeable1 g) => Typeable1 (ApF f g) where
typeOf1 t = mkTyConApp apFTyCon [typeOf1 (f t)] where
f :: ApF f g a -> g (f a)
f = undefined
apTTyCon, apFTyCon :: TyCon
#if __GLASGOW_HASKELL__ < 704
apTTyCon = mkTyCon "Control.Applicative.Trans.Free.ApT"
apFTyCon = mkTyCon "Control.Applicative.Trans.Free.ApF"
#else
apTTyCon = mkTyCon3 "free" "Control.Applicative.Trans.Free" "ApT"
apFTyCon = mkTyCon3 "free" "Control.Applicative.Trans.Free" "ApF"
#endif
{-# NOINLINE apTTyCon #-}
{-# NOINLINE apFTyCon #-}
#endif