{-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeFamilies #-} -- | -- Module : Gauge.Monad -- Copyright : (c) 2009 Neil Brown -- -- License : BSD-style -- Maintainer : bos@serpentine.com -- Stability : experimental -- Portability : GHC -- -- The environment in which most gauge code executes. module Gauge.Monad ( Gauge , Crit (..) , askCrit , askConfig , gaugeIO , withConfig , finallyGauge ) where import Control.Applicative import Control.Exception import Control.Monad (ap) import Data.IORef (IORef, newIORef) import Gauge.Main.Options (Config) import Gauge.Measurement (initializeTime) import System.Random.MWC (GenIO) import Prelude -- Silence redundant import warnings data Crit = Crit { config :: !Config , gen :: !(IORef (Maybe GenIO)) } -- | 'Gauge' is essentially a reader monad to make the benchmark configuration -- available throughout the code. newtype Gauge a = Gauge { runGauge :: Crit -> IO a } instance Functor Gauge where fmap f a = Gauge $ \r -> f <$> runGauge a r instance Applicative Gauge where pure = Gauge . const . pure (<*>) = ap instance Monad Gauge where return = pure ma >>= mb = Gauge $ \r -> runGauge ma r >>= \a -> runGauge (mb a) r -- | Retrieve the configuration from the 'Gauge' monad. askConfig :: Gauge Config askConfig = Gauge (pure . config) askCrit :: Gauge Crit askCrit = Gauge pure -- | Lift an IO action into the 'Gauge' monad. gaugeIO :: IO a -> Gauge a gaugeIO = Gauge . const finallyGauge :: Gauge a -> Gauge b -> Gauge a finallyGauge f g = Gauge $ \crit -> do finally (runGauge f crit) (runGauge g crit) -- | Run a 'Gauge' action with the given 'Config'. withConfig :: Config -> Gauge a -> IO a withConfig cfg act = do initializeTime g <- newIORef Nothing runGauge act (Crit cfg g)