objective-1: src/Control/Object/Instance.hs
{-# LANGUAGE GADTs, Rank2Types #-}
module Control.Object.Instance where
import Control.Concurrent.MVar
import Control.Object.Object
import Control.Monad.IO.Class
import Control.Monad
-- | MVar-based instance
data Instance f g where
InstRef :: MVar (Object f g) -> Instance f g
InstLmap :: (forall x. f x -> g x) -> Instance g h -> Instance f h
InstRmap :: Instance f g -> (forall x. g x -> h x) -> Instance f h
instance HProfunctor Instance where
(^>>@) = InstLmap
(@>>^) = InstRmap
-- | Invoke a method with an explicit landing function.
invoke :: MonadIO m => (forall x. g x -> m x) -> Instance f g -> f a -> m a
invoke m (InstRef v) f = do
obj <- liftIO (takeMVar v)
(a, obj') <- m (runObject obj f)
liftIO $ putMVar v obj'
return a
invoke m (InstLmap t i) f = invoke m i (t f)
invoke m (InstRmap i t) f = invoke (m . t) i f
-- | Invoke a method.
(.-) :: MonadIO m => Instance f m -> f a -> m a
(.-) = invoke id
{-# INLINE (.-) #-}
-- | Create a new instance.
new :: MonadIO m => Object f g -> m (Instance f g)
new = liftIO . liftM InstRef . newMVar
{-# INLINE new #-}
-- | Create a new instance, having it sitting on the current environment.
newSettle :: MonadIO m => Object f m -> m (Instance f m)
newSettle = new
{-# INLINE newSettle #-}