Skip to content

Commit 8f4311c

Browse files
committed
Add solutions to the state chapter
1 parent 39d1d35 commit 8f4311c

File tree

9 files changed

+188
-0
lines changed

9 files changed

+188
-0
lines changed

package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ description: Please see the README on GitHub at <https://github.com/Boei
2121

2222
dependencies:
2323
- base >= 4.7 && < 5
24+
- transformers
2425
- hspec
2526
- QuickCheck
2627
- checkers
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module State.ChapterExercises.Exercises where
2+
3+
newtype State s a = State { runState :: s -> (a, s) }
4+
5+
instance Functor (State s) where
6+
fmap f (State g) = State $ \x -> let (a, s) = g x in (f a, s)
7+
8+
instance Applicative (State s) where
9+
pure a = State $ (,) a
10+
(State f) <*> (State g) = State $ \s -> let (ab, s') = f s
11+
(a, s'') = g s
12+
in (ab a, s'')
13+
14+
instance Monad (State s) where
15+
return = pure
16+
(State f) >>= g = State $ \x -> let (a, s) = f x
17+
State h = g a
18+
in h s
19+
20+
-- Question 1
21+
get :: State s s
22+
get = State $ \s -> (s, s)
23+
24+
-- Question 2
25+
put :: s -> State s ()
26+
put s = State $ const ((), s)
27+
28+
-- Question 3
29+
exec :: State s a -> s -> s
30+
exec (State sa) = snd . sa
31+
32+
-- Question 4
33+
eval :: State s a -> s -> a
34+
eval (State sa) = fst . sa
35+
36+
-- Question 5
37+
modify :: (s -> s) -> State s ()
38+
modify f = State $ \s -> ((), f s)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module State.GetACodingJobWithOneWierdTrick.FizzbuzzDifferently where
2+
3+
import Control.Monad
4+
import Control.Monad.Trans.State
5+
6+
fizzBuzz :: Integer -> String
7+
fizzBuzz n
8+
| n `mod` 15 == 0 = "FizzBuzz"
9+
| n `mod` 5 == 0 = "Fizz"
10+
| n `mod` 3 == 0 = "Buzz"
11+
| otherwise = show n
12+
13+
fizzbuzzList :: [Integer] -> [String]
14+
fizzbuzzList list = execState (mapM_ addResult list) []
15+
16+
addResult :: Integer -> State [String] ()
17+
addResult n = do
18+
xs <- get
19+
let result = fizzBuzz n
20+
put (result : xs)
21+
22+
fizzbuzzFromTo :: Integer -> Integer -> [String]
23+
fizzbuzzFromTo a b = fizzbuzzList [b, b-1 ..a]

src/State/ThrowDown/Exercises.hs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module State.ThrowDown.Exercises where
2+
3+
import System.Random
4+
5+
data Die =
6+
DieOne
7+
| DieTwo
8+
| DieThree
9+
| DieFour
10+
| DieFive
11+
| DieSix
12+
deriving (Eq, Show)
13+
14+
intToDie :: Int -> Die
15+
intToDie n =
16+
case n of
17+
1 -> DieOne
18+
2 -> DieTwo
19+
3 -> DieThree
20+
4 -> DieFour
21+
5 -> DieFive
22+
6 -> DieSix
23+
-- Use this tactic _extremely_ sparingly.
24+
x -> error $ "intToDie got non 1-6 integer: " ++ show x
25+
26+
-- Exercise 1
27+
rollsToGetN :: Int -> StdGen -> Int
28+
rollsToGetN limit = go 0 0
29+
where go :: Int -> Int -> StdGen -> Int
30+
go sum count gen
31+
| sum >= limit = count
32+
| otherwise = go (sum + die) (count + 1) nextGen
33+
where (die, nextGen) = randomR (1, 6) gen
34+
35+
-- Exercise 2
36+
rollsCountLogged :: Int -> StdGen -> (Int, [Die])
37+
rollsCountLogged limit = go 0 0 []
38+
where go :: Int -> Int -> [Die] -> StdGen -> (Int, [Die])
39+
go sum count dies gen
40+
| sum >= limit = (count, dies)
41+
| otherwise = go (sum + die) (count + 1) (intToDie die : dies) nextGen
42+
where (die, nextGen) = randomR (1, 6) gen
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{-# LANGUAGE InstanceSigs #-}
2+
module State.WriteStateForYourself.Exercise where
3+
4+
newtype Moi s a = Moi { runMoi :: s -> (a, s) }
5+
6+
instance Functor (Moi s) where
7+
fmap :: (a -> b) -> Moi s a -> Moi s b
8+
fmap f (Moi g) = Moi $ \x -> let (a, s) = g x in (f a, s)
9+
10+
instance Applicative (Moi s) where
11+
pure :: a -> Moi s a
12+
pure a = Moi $ (,) a
13+
(Moi f) <*> (Moi g) = Moi $ \s -> let (ab, s') = f s
14+
(a, s'') = g s
15+
in (ab a, s'')
16+
17+
instance Monad (Moi s) where
18+
return = pure
19+
(>>=) :: Moi s a -> (a -> Moi s b) -> Moi s b
20+
(Moi f) >>= g = Moi $ \x -> let (a, s) = f x
21+
Moi h = g a
22+
in h s
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module State.ChapterExercises.ExercisesSpec where
2+
3+
import Test.Hspec
4+
import State.ChapterExercises.Exercises
5+
6+
spec :: Spec
7+
spec = do
8+
describe "Test get" $ do
9+
it "runState get \"curryIsAmaze\"" $ do
10+
runState get "curryIsAmaze" `shouldBe` ("curryIsAmaze","curryIsAmaze")
11+
describe "Test put" $ do
12+
it "runState (put \"blah\") \"woot\"" $ do
13+
runState (put "blah") "woot" `shouldBe` ((),"blah")
14+
describe "Test exec" $ do
15+
it "exec (put \"wilma\") \"daphne\"" $ do
16+
exec (put "wilma") "daphne" `shouldBe` "wilma"
17+
it "exec get \"scooby papu\"" $ do
18+
exec get "scooby papu" `shouldBe` "scooby papu"
19+
describe "Test eval" $ do
20+
it "eval get \"bunnicula\"" $ do
21+
eval get "bunnicula" `shouldBe` "bunnicula"
22+
it "eval get \"stake a bunny\"" $ do
23+
eval get "stake a bunny" `shouldBe` "stake a bunny"
24+
describe "Test modify" $ do
25+
it "runState (modify (+1)) 0" $ do
26+
runState (modify (+1)) 0 `shouldBe` ((),1)
27+
it "runState (modify (+1) >> modify (+1)) 0" $ do
28+
runState (modify (+1) >> modify (+1)) 0 `shouldBe` ((),2 :: Int)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module State.GetACodingJobWithOneWierdTrick.FizzbuzzDifferentlySpec where
2+
3+
import Test.Hspec
4+
import State.GetACodingJobWithOneWierdTrick.FizzbuzzDifferently
5+
6+
spec :: Spec
7+
spec = do
8+
describe "Test fizzbuzzFromTo" $ do
9+
it "fizzbuzzFromTo 1 15" $ do
10+
fizzbuzzFromTo 1 15 `shouldBe` ["1", "2", "Buzz", "4", "Fizz", "Buzz", "7", "8", "Buzz", "Fizz", "11", "Buzz", "13", "14", "FizzBuzz"]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module State.ThrowDown.ExercisesSpec where
2+
3+
import System.Random
4+
import Test.Hspec
5+
import State.ThrowDown.Exercises
6+
7+
spec :: Spec
8+
spec = do
9+
describe "Test rollsToGetN" $ do
10+
it "roolsToGetN 20" $ do
11+
rollsToGetN 20 (mkStdGen 0) `shouldBe` 5
12+
describe "Test rollsCountLogged" $ do
13+
it "rollsCountLogged 20" $ do
14+
rollsCountLogged 20 (mkStdGen 0) `shouldBe` (5, [DieFive, DieOne, DieFour, DieSix, DieSix])
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module State.WriteStateForYourself.ExerciseSpec where
2+
3+
import Test.Hspec
4+
import State.WriteStateForYourself.Exercise
5+
6+
spec :: Spec
7+
spec = do
8+
describe "Test Functor implementation" $ do
9+
it "runMoi ((+1) <$> (Moi $ \\s -> (0, s))) 0" $ do
10+
runMoi ((+1) <$> (Moi $ \s -> (0, s))) 0 `shouldBe` (1, 0)

0 commit comments

Comments
 (0)