{-# LANGUAGE ExistentialQuantification #-}

module Control.Comonad.Density where

import Control.Comonad
import Control.Comonad.Trans.Class

data Density f a =  b . Density (f b -> a) (f b)

deriving instance Functor (Density f)

instance Applicative f => Applicative (Density f) where
    pure a = Density (pure a) (pure ())
    Density f x <*> Density g y = pure ((f x) (g y))

instance Comonad (Density f) where
    copure (Density f x) = f x
    cut ɯ@(Density _ x) = Density (pure ɯ) x

instance ComonadTrans Density where
    colift (Density f x) = f <<= x

lift :: Comonad ɯ => ɯ a -> Density ɯ a
lift = Density copure