-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapter-23.hs
204 lines (159 loc) · 4.91 KB
/
chapter-23.hs
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
-- I don't want any warnings as exercises will have some warnings.
{-# OPTIONS_GHC -w #-}
{-# LANGUAGE TupleSections #-}
module Chapter_23 where
import System.Random
import Control.Applicative (liftA3)
import Control.Monad.Trans.State
import Control.Monad (replicateM, join)
import System.Random
-- newtype State s a =
-- State { runState :: s -> (a, s) }
-- Six-sided die
data Die =
DieOne
| DieTwo
| DieThree
| DieFour
| DieFive
| DieSix
deriving (Eq, Show)
intToDie :: Int -> Die
intToDie x =
case x of
1 -> DieOne
2 -> DieTwo
3 -> DieThree
4 -> DieFour
5 -> DieFive
6 -> DieSix
_ -> error $ "intToDie got non 1-6 integer: " ++ show x
rollDieThreeTimes :: (Die, Die, Die)
rollDieThreeTimes =
let s = mkStdGen 0
(d1, s1) = randomR (1, 6) s
(d2, s2) = randomR (1, 6) s1
(d3, s3) = randomR (1, 6) s2
in
(intToDie d1, intToDie d2, intToDie d3)
-- rollDie :: State StdGen Die
-- rollDie = state $ do
-- (n, s) <- randomR (1, 6)
-- return (intToDie n, s)
rollDie :: State StdGen Die
rollDie = intToDie <$> state (randomR (1, 6))
rollDieThreeTimes' :: State StdGen (Die, Die, Die)
rollDieThreeTimes' = liftA3 (,,) rollDie rollDie rollDie
nDie :: Int -> State StdGen [Die]
nDie n = replicateM n rollDie
-- Exercises: Roll Your Own
-- 1
-- Refactor rollsToGetTwenty into having the limit be a function argument.
rollsToGetN :: Int -> StdGen -> Int
rollsToGetN n sg = go 0 0 sg
where
go sum count sg
| sum > n = count
| otherwise =
let (d, newSg) = randomR (1, 6) sg
in
go (sum + d) (count + 1) newSg
-- 2
-- Change rollsToGetN to recording the series of die that occurred in addition
-- to the count.
rollsCountLogged :: Int -> StdGen -> (Int, [Die])
rollsCountLogged n sg = go 0 (0, []) sg
where
go sum cds@(count, ds) sg
| sum > n = cds
| otherwise =
let (d, newSg) = randomR (1, 6) sg
in
go (sum + d) (count + 1, intToDie d : ds) newSg
--
newtype Moi s a = Moi { runMoi :: s -> (a, s) }
instance Functor (Moi s) where
fmap f (Moi sas) = Moi $ \s -> let (a, s') = sas s in (f a, s')
instance Applicative (Moi s) where
pure x = Moi (x,)
Moi sfs <*> (Moi sas) =
Moi $ \s ->
let (f, s1) = sfs s
(a, s2) = sas s1 -- ?? Is passing s1 here correct?
in
(f a, s2)
instance Monad (Moi s) where
return = pure
Moi sas >>= famb = join $ Moi $ \s -> let (a, s') = sas s in (famb a, s')
fizzBuzz :: Integer -> String
fizzBuzz n
| n `mod` 15 == 0 = "FizzBuzz"
| n`mod`5 == 0 = "Buzz"
| n`mod`3 == 0 = "Fizz"
| otherwise = show n
fizzbuzzList :: [Integer] -> [String]
fizzbuzzList list = execState (mapM_ addResult list) []
addResult :: Integer -> State [String] ()
addResult n = do
xs <- get
let result = fizzBuzz n
put (result : xs)
main :: IO ()
main = mapM_ putStrLn $ reverse $ fizzbuzzList [1..100]
-- Fizzbuzz Differently
{-
It’s an exercise! Rather than changing the underlying data structure, fix our --
reversing fizzbuzz by changing the code in the following way: --
--
fizzbuzzFromTo :: Integer -> Integer -> [String] --
fizzbuzzFromTo = undefined --
--
Continue to use consing in the construction of the result list, but have it come --
out in the right order to begin with by enumerating the sequence backwards. This --
sort of tactic is more commonly how you’ll want to fix your code when you’re --
quashing unnecessary reversals. --
-}
fizzbuzzFromTo :: Integer -> Integer -> [String]
fizzbuzzFromTo from to = map fizzBuzz $ enumFromThenTo to (to - 1) from
-- Chapter exercises
-- Write the following functions. You’ll want to use your own State type for
-- which you’ve defined the Functor, Applicative, and Monad.
-- 1
-- Construct a State where the state is also the value you return.
get' :: State s s
get' = state $ \s -> (s, s)
-- Expected output
-- Prelude> runState get' "curryIsAmaze"
-- ("curryIsAmaze","curryIsAmaze")
-- 2
-- Construct a State where the resulting state is the argument pro- vided and
-- the value is defaulted to unit.
put':: s -> State s ()
put' s = state $ const ((), s)
-- Prelude> runState (put' "blah") "woot"
-- ((),"blah")
-- 3
-- Run the State with 𝑠 and get the state that results.
exec' :: State s a -> s -> s
exec' sa = snd . runState sa
-- Prelude> exec' (put' "wilma") "daphne"
-- "wilma"
-- Prelude> exec' get' "scooby papu"
-- "scooby papu"
-- 4
-- Run the State with s and get the value that results.
eval' :: State s a -> s -> a
eval' sa = fst . runState sa
-- Prelude> eval' get' "bunnicula"
-- "bunnicula"
-- Prelude> eval' get' "stake a bunny"
-- "stake a bunny"
-- 5
--Write a function which applies a function to create a new State.
modify'' :: (s -> s) -> State s () -- Since modify' is already there.
modify'' f = state $ \s -> ((), f s)
-- Should behave like the following:
-- Prelude> runState (modify'' (+1)) 0
-- ((),1)
-- Prelude> runState (modify'' (+1) >> modify'' (+1)) 0
-- ((),2)