{-# LANGUAGE CPP, TypeFamilies #-} #if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Safe #-} #endif ----------------------------------------------------------------------------- -- The fuel monad ----------------------------------------------------------------------------- module Compiler.Hoopl.Fuel ( Fuel, infiniteFuel, fuelRemaining , withFuel , FuelMonad(..) , FuelMonadT(..) , CheckingFuelMonad , InfiniteFuelMonad , SimpleFuelMonad ) where import Compiler.Hoopl.Checkpoint import Compiler.Hoopl.Unique import Control.Applicative (Applicative(..)) import Control.Monad (ap,liftM) class Monad m => FuelMonad m where getFuel :: m Fuel setFuel :: Fuel -> m () -- | Find out how much fuel remains after a computation. -- Can be subtracted from initial fuel to get total consumption. fuelRemaining :: FuelMonad m => m Fuel fuelRemaining = getFuel class FuelMonadT fm where runWithFuel :: (Monad m, FuelMonad (fm m)) => Fuel -> fm m a -> m a liftFuel :: (Monad m, FuelMonad (fm m)) => m a -> fm m a type Fuel = Int withFuel :: FuelMonad m => Maybe a -> m (Maybe a) withFuel Nothing = return Nothing withFuel (Just a) = do f <- getFuel if f == 0 then return Nothing else setFuel (f-1) >> return (Just a) ---------------------------------------------------------------- newtype CheckingFuelMonad m a = FM { unFM :: Fuel -> m (a, Fuel) } instance Monad m => Functor (CheckingFuelMonad m) where fmap = liftM instance Monad m => Applicative (CheckingFuelMonad m) where pure = return (<*>) = ap instance Monad m => Monad (CheckingFuelMonad m) where return a = FM (\f -> return (a, f)) fm >>= k = FM (\f -> do { (a, f') <- unFM fm f; unFM (k a) f' }) instance CheckpointMonad m => CheckpointMonad (CheckingFuelMonad m) where type Checkpoint (CheckingFuelMonad m) = (Fuel, Checkpoint m) checkpoint = FM $ \fuel -> do { s <- checkpoint ; return ((fuel, s), fuel) } restart (fuel, s) = FM $ \_ -> do { restart s; return ((), fuel) } instance UniqueMonad m => UniqueMonad (CheckingFuelMonad m) where freshUnique = FM (\f -> do { l <- freshUnique; return (l, f) }) instance Monad m => FuelMonad (CheckingFuelMonad m) where getFuel = FM (\f -> return (f, f)) setFuel f = FM (\_ -> return ((),f)) instance FuelMonadT CheckingFuelMonad where runWithFuel fuel m = do { (a, _) <- unFM m fuel; return a } liftFuel m = FM $ \f -> do { a <- m; return (a, f) } ---------------------------------------------------------------- newtype InfiniteFuelMonad m a = IFM { unIFM :: m a } instance Monad m => Functor (InfiniteFuelMonad m) where fmap = liftM instance Monad m => Applicative (InfiniteFuelMonad m) where pure = return (<*>) = ap instance Monad m => Monad (InfiniteFuelMonad m) where return a = IFM $ return a m >>= k = IFM $ do { a <- unIFM m; unIFM (k a) } instance UniqueMonad m => UniqueMonad (InfiniteFuelMonad m) where freshUnique = IFM $ freshUnique instance Monad m => FuelMonad (InfiniteFuelMonad m) where getFuel = return infiniteFuel setFuel _ = return () instance CheckpointMonad m => CheckpointMonad (InfiniteFuelMonad m) where type Checkpoint (InfiniteFuelMonad m) = Checkpoint m checkpoint = IFM checkpoint restart s = IFM $ restart s instance FuelMonadT InfiniteFuelMonad where runWithFuel _ = unIFM liftFuel = IFM infiniteFuel :: Fuel -- effectively infinite, any, but subtractable infiniteFuel = maxBound type SimpleFuelMonad = CheckingFuelMonad SimpleUniqueMonad {- runWithFuelAndUniques :: Fuel -> [Unique] -> FuelMonad a -> a runWithFuelAndUniques fuel uniques m = a where (a, _, _) = unFM m fuel uniques freshUnique :: FuelMonad Unique freshUnique = FM (\f (l:ls) -> (l, f, ls)) -}