module Exercises where import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Reader (Reader(..), ReaderT(..), runReader, runReaderT) import Control.Monad.Trans.State (StateT(..)) import Data.Functor.Identity (Identity(..)) -- 1. rDec is a function that should get its argument in the context of -- Reader and return a value decremented by one. -- -- Note that “Reader” from transformers is ReaderT of Identity and -- that runReader is a convenience function throwing away the -- meaningless structure for you. Play with runReaderT if you like. rDec :: Num a => Reader a a rDec = ReaderT $ dec where dec :: Num a => a -> Identity a dec = return . (flip (-) 1) -- 2. Once you have an rDec that works, make it and any inner lamb- -- das pointfree if that’s not already the case. -- 3. rShow is show, but in Reader. rShow :: Show a => Reader a String rShow = ReaderT $ toString where toString = return . show -- 4. Once you have an rShow that works, make it pointfree. -- 5. rPrintAndInc will first print the input with a greeting, then return -- the input incremented by one. rPrintAndInc :: (Num a, Show a) => ReaderT a IO a rPrintAndInc = ReaderT print where print x = do liftIO $ putStrLn $ "Hi: " ++ show x return $ x + 1 -- Prelude> runReaderT rPrintAndInc 1 -- Hi: 1 -- 2 -- Prelude> traverse (runReaderT rPrintAndInc) [1..10] -- Hi: 1 -- Hi: 2 -- Hi: 3 -- Hi: 4 -- Hi: 5 -- Hi: 6 -- Hi: 7 -- Hi: 8 -- Hi: 9 -- Hi: 10 -- [2,3,4,5,6,7,8,9,10,11] -- 6. sPrintIncAccum first prints the input with a greeting, then puts -- the incremented input as the new state, and returns the original -- input as a String. sPrintIncAccum :: (Num a, Show a) => StateT a IO String sPrintIncAccum = StateT print where print x = do liftIO $ putStrLn $ "Hi: " ++ show x return $ (show x, x + 1) -- Prelude> runStateT sPrintIncAccum 10 -- Hi: 10 -- ("10",11) -- Prelude> mapM (runStateT sPrintIncAccum) [1..5] -- Hi: 1 -- Hi: 2 -- Hi: 3 -- Hi: 4 -- Hi: 5 -- [("1",2),("2",3),("3",4),("4",5),("5",6)]