summaryrefslogtreecommitdiff
path: root/Haskell-book/26/Exercises/src/Exercises.hs
blob: d3a83708f2fbe624c8d062df8aa28afe52c5c8a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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)]