{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main where
import Counter
import Weather
newtype MyAppM m a = MyAppM { unMyAppM :: MockCounter (MockWeather m) a }
deriving (Functor, Applicative, Monad, CounterT, WeatherT)
instance Monad m => WeatherT (MockCounter (MockWeather m))
runMyAppM :: Int -> MyAppM m a -> m (a, Int)
runMyAppM i = runMockWeather . (`runMockCounter` i) . unMyAppM
myApp :: (Monad m, CounterT m , WeatherT m) => m String
myApp = do
_ <- increment
(WeatherData weather) <- byCity "Amsterdam"
return weather
main :: IO ()
main = runMyAppM 12 myApp >>= print
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Weather where
import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Trans.Identity
import Control.Monad.Trans.Maybe
import Control.Monad.Writer
newtype WeatherData = WeatherData String deriving (Show)
class Monad m => WeatherT m where
byCity :: String -> m WeatherData
default byCity :: (MonadTrans t, WeatherT m', m ~ t m') => String -> m WeatherData
byCity = lift . byCity
instance WeatherT m => WeatherT (ExceptT e m)
instance WeatherT m => WeatherT (MaybeT m)
instance WeatherT m => WeatherT (ReaderT r m)
instance WeatherT m => WeatherT (StateT s m)
instance (Monoid w, WeatherT m) => WeatherT (WriterT w m)
newtype MockWeather m a = MockWeather {
unMockWeather :: IdentityT m a
} deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MonadError e, MonadReader r, MonadWriter w)
runMockWeather :: MockWeather f a -> f a
runMockWeather = runIdentityT . unMockWeather
instance Monad m => WeatherT (MockWeather m) where
byCity city = MockWeather $ return $ WeatherData $ "It is sunny in " ++ city
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Counter where
import Control.Monad.Except
import Control.Monad.Identity
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Trans.Maybe
import Control.Monad.Writer
class Monad m => CounterT m where
increment :: m Int
current :: m Int
default increment :: (MonadTrans t, CounterT m', m ~ t m') => m Int
increment = lift increment
default current :: (MonadTrans t, CounterT m', m ~ t m') => m Int
current = lift current
instance CounterT m => CounterT (ExceptT e m)
instance CounterT m => CounterT (MaybeT m)
instance CounterT m => CounterT (ReaderT r m)
instance CounterT m => CounterT (StateT s m)
instance (Monoid w, CounterT m) => CounterT (WriterT w m)
newtype MockCounter m a = MockCounter {
unMockCounter :: StateT Int m a
} deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MonadError e, MonadReader r, MonadWriter w, MonadState Int)
defaultMockCounter :: MockCounter Identity ()
defaultMockCounter = MockCounter $ put 0
runMockCounter :: MockCounter m a -> Int -> m (a, Int)
runMockCounter = runStateT . unMockCounter
instance Monad m => CounterT (MockCounter m) where
increment = MockCounter $ do
c <- get
let n = c + 1
put n
return n
current = MockCounter get