module Ermine.Unification.Sharing
( runSharing
, withSharing
, sharing
, SharingT(..)
, Shared(..)
, uncaring
) where
import Control.Applicative
import Control.Monad (void)
import Control.Monad.Writer.Class
import Control.Monad.Reader.Class
import Control.Monad.State.Class
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
import Control.Comonad
import Data.Foldable
import Data.Monoid
import Data.Traversable
import Data.Data
data Shared a = Shared !Bool a
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable,Typeable,Data)
instance Comonad Shared where
extract (Shared _ a) = a
extend f s@(Shared b _) = Shared b (f s)
newtype SharingT m a = SharingT { unsharingT :: m (Shared a) }
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
deriving Typeable
#endif
instance Monad m => Functor (SharingT m) where
fmap f (SharingT m) = SharingT $ do
Shared p a <- m
return $! Shared p (f a)
instance Monad m => Applicative (SharingT m) where
pure a = SharingT (return (Shared False a))
SharingT mf <*> SharingT ma = SharingT $ do
Shared p f <- mf
Shared q a <- ma
return $! Shared (p || q) (f a)
instance Monad m => Monad (SharingT m) where
return a = SharingT (return (Shared False a))
SharingT m >>= f = SharingT $ do
Shared p a <- m
Shared q b <- unsharingT (f a)
return $! Shared (p || q) b
instance Monad m => MonadWriter Any (SharingT m) where
tell (Any p) = SharingT $ return $ Shared p ()
listen (SharingT ma) = SharingT $ do
Shared p a <- ma
return $! Shared p (a, Any p)
pass (SharingT mapp) = SharingT $ do
Shared p (a, pp) <- mapp
return $! Shared (getAny (pp (Any p))) a
instance MonadTrans SharingT where
lift ma = SharingT $ do
a <- ma
return $! Shared False a
instance MonadIO m => MonadIO (SharingT m) where
liftIO = lift . liftIO
instance MonadState s m => MonadState s (SharingT m) where
get = lift get
put = lift . put
instance MonadReader e m => MonadReader e (SharingT m) where
ask = lift ask
local f = SharingT . local f . unsharingT
runSharing :: Monad m => a -> SharingT m a -> m a
runSharing a m = do
Shared modified b <- unsharingT m
return $! if modified then b else a
withSharing :: Monad m => (a -> SharingT m a) -> a -> m a
withSharing k a = runSharing a (k a)
uncaring :: Functor m => SharingT m a -> m ()
uncaring = void . unsharingT
sharing :: MonadWriter Any m => a -> m a -> m a
sharing a m = do
(b, Any modified) <- listen m
return $! if modified then b else a