packages feed

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