{-# LANGUAGE StaticPointers #-}

module Control.Comonad.Static where

import Control.Distributed.Closure
import Data.Functor.Static
import Data.Typeable (Typeable)

-- | Instances of 'StaticExtend' should satisfy the following laws:
--
-- @
-- 'staticExtend' f = 'staticMap' f . 'staticDuplicate'
-- 'staticDuplicate' = 'staticExtend' (static 'id')
-- 'staticExtend' f . 'staticExtend' g = 'staticExtend' (static (.) `cap` f `cap` 'staticExtend' g)
-- 'staticDuplicate' . 'staticDuplicate' = 'staticMap' (static 'staticDuplicate') . 'staticDuplicate'
-- @
class StaticFunctor w => StaticExtend w where
  staticDuplicate :: Typeable a => w a -> w (w a)
  staticDuplicate = forall (w :: * -> *) a b.
(StaticExtend w, Typeable a, Typeable b) =>
Closure (w a -> b) -> w a -> w b
staticExtend (static forall a. a -> a
id)

  staticExtend :: (Typeable a, Typeable b) => Closure (w a -> b) -> w a -> w b
  staticExtend Closure (w a -> b)
sf = forall (f :: * -> *) a b.
(StaticFunctor f, Typeable a, Typeable b) =>
Closure (a -> b) -> f a -> f b
staticMap Closure (w a -> b)
sf forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (w :: * -> *) a.
(StaticExtend w, Typeable a) =>
w a -> w (w a)
staticDuplicate

  {-# MINIMAL staticDuplicate | staticExtend #-}

class StaticExtend w => StaticComonad w where
  staticExtract :: Typeable a => w a -> a

instance StaticExtend Closure where
  staticDuplicate :: forall a. Typeable a => Closure a -> Closure (Closure a)
staticDuplicate = forall a. Closure a -> Closure (Closure a)
cduplicate

instance StaticComonad Closure where
  staticExtract :: forall a. Typeable a => Closure a -> a
staticExtract = forall a. Closure a -> a
unclosure