parsley-0.1.1.0: src/ghc/Parsley/Internal/Common/Fresh.hs
{-# LANGUAGE FunctionalDependencies,
GeneralisedNewtypeDeriving,
DerivingStrategies,
UndecidableInstances #-}
module Parsley.Internal.Common.Fresh (
VFreshT, HFreshT, VFresh, HFresh,
runFreshT, runFresh,
evalFreshT, evalFresh,
execFreshT, execFresh,
MonadFresh(..), construct, mapVFreshT,
RunFreshT
) where
import Control.Applicative (liftA2)
import Control.Monad.Fix (MonadFix(..))
import Control.Monad.Identity (Identity, runIdentity)
import Control.Monad.Reader.Class (MonadReader(..))
import Control.Monad.State.Class (MonadState(..))
import Control.Monad.Trans (MonadTrans(..), MonadIO(..))
-- Fresh operations
class Monad m => MonadFresh x m | m -> x where
newVar :: m x
newScope :: m a -> m a
construct :: MonadFresh x m => (x -> a) -> m a
construct f = fmap f newVar
mapVFreshT :: (m (a, x, x) -> n (b, x, x)) -> VFreshT x m a -> VFreshT x n b
mapVFreshT f m = vFreshT (\cur max -> f (unVFreshT m cur max))
class (Monad n, Monad m) => RunFreshT x n m | m -> x, m -> n where
runFreshT :: m a -> x -> n (a, x)
evalFreshT :: RunFreshT x n m => m a -> x -> n a
evalFreshT m init = fst <$> runFreshT m init
execFreshT :: RunFreshT x n m => m a -> x -> n x
execFreshT m init = snd <$> runFreshT m init
-- Fresh type
type HFresh x = HFreshT x Identity
type VFresh x = VFreshT x Identity
-- TODO Nominals
newtype VFreshT x m a = VFreshT (FreshT x m a) deriving newtype (Functor, Applicative, Monad, MonadFix, MonadTrans, MonadIO, MonadReader r, MonadState s, RunFreshT x m)
newtype HFreshT x m a = HFreshT (FreshT x m a) deriving newtype (Functor, Applicative, Monad, MonadFix, MonadTrans, MonadIO, MonadReader r, MonadState s, RunFreshT x m)
newtype FreshT x m a = FreshT {unFreshT :: x -> x -> m (a, x, x)}
instance Monad n => RunFreshT x n (FreshT x n) where
runFreshT k init =
do (x, _, max) <- unFreshT k init init
return $! (x, max)
runFresh :: RunFreshT x Identity m => m a -> x -> (a, x)
runFresh mx = runIdentity . runFreshT mx
evalFresh :: RunFreshT x Identity m => m a -> x -> a
evalFresh mx = runIdentity . evalFreshT mx
execFresh :: RunFreshT x Identity m => m a -> x -> x
execFresh mx = runIdentity . execFreshT mx
vFreshT :: (x -> x -> m (a, x, x)) -> VFreshT x m a
vFreshT = VFreshT . FreshT
unVFreshT :: VFreshT x m a -> x -> x -> m (a, x, x)
unVFreshT (VFreshT f) = unFreshT f
hFreshT :: (x -> x -> m (a, x, x)) -> HFreshT x m a
hFreshT = HFreshT . FreshT
unHFreshT :: HFreshT x m a -> x -> x -> m (a, x, x)
unHFreshT (HFreshT f) = unFreshT f
instance Functor f => Functor (FreshT x f) where
{-# INLINE fmap #-}
fmap f (FreshT k) = FreshT (\cur max -> fmap (\(x, cur', max') -> (f x, cur', max')) (k cur max))
instance Monad m => Applicative (FreshT x m) where
{-# INLINE pure #-}
pure x = FreshT (\cur max -> pure (x, cur, max))
{-# INLINE liftA2 #-}
liftA2 f (FreshT mx) (FreshT my) = FreshT (\cur max ->
do (x, cur', max') <- mx cur max
(y, cur'', max'') <- my cur' max'
return $! (f x y, cur'', max''))
instance Monad m => Monad (FreshT x m) where
{-# INLINE return #-}
return = pure
{-# INLINE (>>=) #-}
(FreshT mx) >>= f = FreshT (\cur max ->
do (x, cur', max') <- mx cur max
unFreshT (f x) cur' max')
instance MonadFix m => MonadFix (FreshT x m) where
{-# INLINE mfix #-}
mfix f = FreshT (\cur max -> mfix (\ ~(x, _, _) -> unFreshT (f x) cur max))
instance MonadTrans (FreshT x) where
{-# INLINE lift #-}
lift m = FreshT (\cur max ->
do x <- m
return (x, cur, max))
instance (Monad m, Ord x, Enum x) => MonadFresh x (VFreshT x m) where
newVar = vFreshT (\cur m -> return (cur, cur, max m cur))
newScope scoped = vFreshT (\cur max ->
do (x, _, max') <- unVFreshT scoped (succ cur) max
return $! (x, cur, max'))
instance (Monad m, Ord x, Enum x) => MonadFresh x (HFreshT x m) where
newVar = hFreshT (\cur m -> return (cur, succ cur, max m cur))
newScope scoped = hFreshT (\cur max ->
do (x, _, max') <- unHFreshT scoped cur max
return $! (x, cur, max'))
instance MonadIO m => MonadIO (FreshT x m) where liftIO = lift . liftIO
instance MonadReader r m => MonadReader r (FreshT x m) where
ask = lift ask
local f m = FreshT (\cur next -> local f (unFreshT m cur next))
instance MonadState s m => MonadState s (FreshT x m) where
get = lift get
put = lift . put