{-# LANGUAGE
GADTs #-}
module ApNormalize.Aps
(
Aps(..)
, (<$>^)
, (<*>^)
, liftAps
, lowerAps
, liftA2Aps
, apsToApDList
) where
import Control.Applicative (liftA2, liftA3)
import ApNormalize.DList
data Aps f a where
Pure :: a -> Aps f a
FmapLift :: (x -> a) -> f x -> Aps f a
LiftA2Aps :: (x -> y -> z -> a) -> f x -> f y -> ApDList f z -> Aps f a
infixl 4 <$>^, <*>^
(<$>^) :: (a -> b) -> f a -> Aps f b
(<$>^) = FmapLift
{-# INLINE (<$>^) #-}
(<*>^) :: Applicative f => Aps f (a -> b) -> f a -> Aps f b
u <*>^ v = u <*> liftAps v
{-# INLINE (<*>^) #-}
liftAps :: f a -> Aps f a
liftAps = FmapLift id
{-# INLINE liftAps #-}
lowerAps :: Applicative f => Aps f a -> f a
lowerAps (Pure x) = pure x
lowerAps (FmapLift f u) = fmap f u
lowerAps (LiftA2Aps f u v w) =
lowerApDList (Yoneda (\k -> liftA2 (\x y -> k (f x y)) u v)) w
{-# INLINE lowerAps #-}
instance Functor (Aps f) where
fmap f (Pure x) = Pure (f x)
fmap f (FmapLift g u) = FmapLift (f . g) u
fmap f (LiftA2Aps g u v w) = LiftA2Aps ((fmap . fmap . fmap) f g) u v w
{-# INLINE fmap #-}
instance Applicative f => Applicative (Aps f) where
pure = Pure
Pure f <*> uy = fmap f uy
FmapLift f ux <*> uy = liftA2Aps f ux uy
LiftA2Aps f u v w <*> ww =
LiftA2Aps (\x y (z, zz) -> f x y z zz) u v (liftA2 (,) w (apsToApDList ww))
{-# INLINE pure #-}
{-# INLINE (<*>) #-}
liftA2Aps :: Applicative f => (a -> b -> c) -> f a -> Aps f b -> Aps f c
liftA2Aps f ux (Pure y) = FmapLift (\x -> f x y) ux
liftA2Aps f ux (FmapLift g uy) = LiftA2Aps (\x y _ -> f x (g y)) ux uy (pure ())
liftA2Aps f ux (LiftA2Aps g u v w) =
LiftA2Aps (\x y (z, zz) -> f x (g y z zz)) ux u (liftA2 (,) (liftApDList v) w)
{-# INLINE liftA2Aps #-}
apsToApDList :: Applicative f => Aps f a -> ApDList f a
apsToApDList (Pure x) = pure x
apsToApDList (FmapLift f u) = fmap f (liftApDList u)
apsToApDList (LiftA2Aps f u v w) = liftA3 f (liftApDList u) (liftApDList v) w
{-# INLINE apsToApDList #-}