{-# OPTIONS_GHC -fglasgow-exts #-} module NarrowContext where import Control.Comonad import Control.Functor.Pointed import Control.Applicative import Control.Comonad.Context class Applicative ((:~*) e) => NarrowMemo e where data (:~*) e :: * -> * data D e :: * apply :: (e :~* r) -> D e -> r memo :: (D e -> r) -> (e :~* r) domain :: D e -> e instance NarrowMemo Bool where data Bool :~* a = MemoBool a a data D Bool = DTrue | DFalse apply (MemoBool o1 o2) DTrue = o1 apply (MemoBool o1 o2) DFalse = o2 memo f = MemoBool (f DTrue) (f DFalse) domain DTrue = True domain DFalse = False instance Functor ((:~*) Bool) where fmap f (MemoBool a b) = MemoBool (f a) (f b) instance Applicative ((:~*) Bool) where pure x = MemoBool x x MemoBool f g <*> MemoBool a b = MemoBool (f a) (g b) instance Pointed ((:~*) Bool) where point x = MemoBool x x instance (NarrowMemo a, NarrowMemo b) => NarrowMemo (Either a b) where data Either a b :~* e = MemoEither (a :~* e) (b :~* e) data D (Either a b) = DLeft (D a) | DRight (D b) apply (MemoEither l _) (DLeft a) = apply l a apply (MemoEither _ r) (DRight b) = apply r b memo f = MemoEither (memo (f . DLeft)) (memo (f . DRight)) domain (DLeft a) = Left (domain a) domain (DRight b) = Right (domain b) instance (NarrowMemo a, NarrowMemo b) => Functor ((:~*) (Either a b)) where fmap f (MemoEither a b) = MemoEither (fmap f a) (fmap f b) instance (NarrowMemo a, NarrowMemo b) => Applicative ((:~*) (Either a b)) where pure f = MemoEither (pure f) (pure f) MemoEither f g <*> MemoEither a b = MemoEither (f <*> a) (g <*> b) instance (NarrowMemo a, NarrowMemo b) => NarrowMemo (a,b) where data (a,b) :~* e = MemoBoth (a :~* (b :~* e)) data D (a,b) = DBoth (D a) (D b) apply (MemoBoth f) (DBoth a b) = apply (apply f a) b memo f = MemoBoth $ memo $ \a -> memo (f . DBoth a) domain (DBoth a b) = (domain a, domain b) instance (NarrowMemo a, NarrowMemo b) => Functor ((:~*) (a,b)) where fmap f (MemoBoth g) = MemoBoth (fmap (fmap f) g) instance (NarrowMemo a, NarrowMemo b) => Applicative ((:~*) (a,b)) where pure = MemoBoth . pure . pure f <*> a = MemoBoth $ memo $ \da -> memo $ \db -> let e = DBoth da db in apply f e (apply a e) data NarrowContext e a = NarrowContext (e :~* a) (D e) instance NarrowMemo e => Functor (NarrowContext e) where fmap f (NarrowContext t d) = NarrowContext (memo (f . apply t)) d instance NarrowMemo e => Copointed (NarrowContext e) where extract (NarrowContext t d) = apply t d instance NarrowMemo e => Comonad (NarrowContext e) where duplicate (NarrowContext f a) = NarrowContext (memo (NarrowContext f)) a instance NarrowMemo e => ComonadContext (D e) (NarrowContext e) where getC (NarrowContext _ e) = e modifyC f (NarrowContext g e) = apply g (f e)