Monad Transformers
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main where
import Counter
import Weather
import MockWeather
import MockCounter
import Control.Monad.Trans.Class
-- 'someApp' works for any underlying monad 'm'
-- and any instance of 'MonadCounter'
-- and any instance of 'MonadWeather'
someApp :: (Monad m, MonadCounter m , MonadWeather m) => m String
someApp = do
_ <- increment
(WeatherData weather) <- byCity "Amsterdam"
return weather
newtype MyAppM m a = MyAppM { unMyAppM :: MockCounter (MockWeather m) a }
deriving (Functor, Applicative, Monad, MonadCounter, MonadWeather)
instance MonadTrans MyAppM where
lift = MyAppM . lift . lift
runMyAppM :: Int -> MyAppM m a -> m (a, Int)
runMyAppM i = runMockWeather . (`runMockCounter` i) . unMyAppM
-- set the underlying monad to 'IO'
-- and 'MonadCounter' instance to 'MockCounter'
-- and 'MonadWeather' instance to 'MockWeather'
main :: IO ()
main = runMyAppM 12 (someApp >> someApp) >>= print
INFO