Skip to content

Commit 3bdf093

Browse files
committed
Add solutions to the folding lists chapter
1 parent 866308c commit 3bdf093

File tree

9 files changed

+254
-0
lines changed

9 files changed

+254
-0
lines changed

package.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ dependencies:
3636
- split
3737
- scotty
3838
- wai
39+
- time
3940

4041
library:
4142
source-dirs: src
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module FoldingLists.ChapterExercises.RewritingFunctionsUsingFolds where
2+
3+
myOr :: [Bool] -> Bool
4+
myOr = foldr (||) False
5+
6+
myAny :: (a -> Bool) -> [a] -> Bool
7+
myAny f = foldr go True
8+
where go x = (&&) (f x)
9+
10+
myElem :: Eq a => a -> [a] -> Bool
11+
myElem x = any ((==) x)
12+
13+
myReverse :: [a] -> [a]
14+
myReverse = foldl (flip (:)) []
15+
16+
myMap :: (a -> b) -> [a] -> [b]
17+
myMap f = foldr (\x acc -> f x : acc) []
18+
19+
myFilter :: (a -> Bool) -> [a] -> [a]
20+
myFilter f = foldr (\x acc -> if f x then x : acc else acc) []
21+
22+
squish :: [[a]] -> [a]
23+
squish = foldr (++) []
24+
25+
squishMap :: (a -> [b]) -> [a] -> [b]
26+
squishMap f = foldr (\x acc -> f x ++ acc) []
27+
28+
squishAgain :: [[a]] -> [a]
29+
squishAgain = squishMap id
30+
31+
myMaximumBy :: (a -> a -> Ordering) -> [a] -> a
32+
myMaximumBy f = foldr1 go
33+
where go x acc = case f x acc of
34+
GT -> x
35+
otherwise -> acc
36+
37+
myMinimumBy :: (a -> a -> Ordering) -> [a] -> a
38+
myMinimumBy f = foldr1 go
39+
where go x acc = case f x acc of
40+
LT -> x
41+
otherwise -> acc
42+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module FoldingLists.ChapterExercises.WarmUpAndReview where
2+
3+
-- Question 1
4+
stops = "pbtdkg"
5+
vowels = "aeiou"
6+
7+
stopVowelStop :: [(Char, Char, Char)]
8+
stopVowelStop = [(x, y, z) | x <- stops, y <- vowels, z <- stops]
9+
10+
stopVowelStop' :: [(Char, Char, Char)]
11+
stopVowelStop' = filter go stopVowelStop
12+
where go ('p', _, _) = True
13+
go _ = False
14+
15+
-- Question 2
16+
-- This function calculates the average word length in a sentence
17+
seekritFunc x =
18+
div (sum (map length (words x)))
19+
(length (words x))
20+
21+
-- Question 3
22+
seekritFunc' x = y / z
23+
where y = fromIntegral $ sum $ map length $ words x
24+
z = fromIntegral $ length $ words x
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
## Question 1
2+
3+
`foldr (*) 1 [1..5]` will return the same result as
4+
`b) foldl (flip (*)) 1 [1..5]` and
5+
`c) foldl (*) 1 [1..5]`.
6+
7+
## Question 2
8+
9+
```haskell
10+
foldl (flip (*)) 1 [1..3]
11+
flip (*) (flip (*) (flip (*) 1 1) 2) 3
12+
flip (*) (flip (*) (1 * 1) 2) 3
13+
flip (*) (flip (*) 1 2) 3
14+
flip (*) (2 * 1) 3
15+
flip (*) 2 3
16+
3 * 2
17+
6
18+
```
19+
20+
## Question 3
21+
22+
One difference between `foldr` and `foldl` is
23+
`c) foldr , but not foldl , associates to the right`.
24+
25+
## Question 4
26+
27+
Folds are catamorphisms,
28+
which means they are generally used to
29+
`a) reduce structure`.
30+
31+
## Question 5
32+
33+
a) foldr (++) "" ["woot", "WOOT", "woot"]
34+
b) foldr max 'a' "fear is the little death"
35+
c) foldr (&&) True [False, True]
36+
d) foldr (||) False [False, True]
37+
e) foldl (\acc x -> acc ++ show x) "" [1..5]
38+
f) foldl const 'a' [1..5]
39+
g) foldl const 0 "tacos"
40+
h) foldr (flip const) 0 "burritos"
41+
i) foldr (flip const) 'z' [1..5]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module FoldingLists.HowToWriteFoldFunctions.IntermissionExercises where
2+
3+
import Data.List
4+
import Data.Ord
5+
import Data.Time
6+
7+
data DatabaseItem = DbString String
8+
| DbNumber Integer
9+
| DbDate UTCTime
10+
deriving (Eq, Ord, Show)
11+
12+
-- Question 1
13+
filterDbDate :: [DatabaseItem] -> [UTCTime]
14+
filterDbDate = foldr go []
15+
where go (DbDate t) acc = t : acc
16+
go _ acc = acc
17+
18+
-- Question 2
19+
filterDbNumber :: [DatabaseItem] -> [Integer]
20+
filterDbNumber = foldr go []
21+
where go (DbNumber x) acc = x : acc
22+
go _ acc = acc
23+
24+
-- Question 3
25+
-- Descending sort https://ro-che.info/articles/2016-04-02-descending-sort-haskell
26+
mostRecent :: [DatabaseItem] -> UTCTime
27+
mostRecent = head . sortOn Down . filterDbDate
28+
29+
-- Question 4
30+
sumDb :: [DatabaseItem] -> Integer
31+
sumDb = sum . filterDbNumber
32+
33+
-- Question 5
34+
avgDb :: [DatabaseItem] -> Double
35+
avgDb = avg . filterDbNumber
36+
where avg :: [Integer] -> Double
37+
avg xs = s / l
38+
where s = fromIntegral $ sum xs
39+
l = fromIntegral $ length xs
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module FoldingLists.Scans.ScansExercises where
2+
3+
import Data.List
4+
5+
-- Question 1
6+
fibs :: [Integer]
7+
fibs = scanl (+) 1 fibs
8+
9+
fibs' :: [Integer]
10+
fibs' = take 20 fibs
11+
12+
-- Question 2
13+
fibs'' :: [Integer]
14+
fibs'' = takeWhile (<100) fibs
15+
16+
-- Question 3
17+
factorial :: [Integer]
18+
factorial = scanl (*) 1 [2..]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module FoldingLists.ChapterExercises.RewritingFunctionsUsingFoldsSpec where
2+
3+
import Test.Hspec
4+
import FoldingLists.ChapterExercises.RewritingFunctionsUsingFolds
5+
6+
spec :: Spec
7+
spec = do
8+
describe "Test myAny" $ do
9+
it "myAny even [1, 3, 5]" $ do
10+
myAny even [1, 3, 5] `shouldBe` False
11+
it "myAny odd [1, 3, 5]" $ do
12+
myAny odd [1, 3, 5] `shouldBe` True
13+
describe "Test myElem" $ do
14+
it "myElem 1 [1..10]" $ do
15+
myElem 1 [1..10] `shouldBe` True
16+
it "myElem 1 [2..10]" $ do
17+
myElem 1 [2..10] `shouldBe` False
18+
describe "Test myReverse" $ do
19+
it "myReverse \"blah\"" $ do
20+
myReverse "blah" `shouldBe` "halb"
21+
it "myReverse [1..5]" $ do
22+
myReverse [1..5] `shouldBe` [5,4,3,2,1]
23+
describe "Test squishMap" $ do
24+
it "squishMap (\\x -> [1, x, 3]) [2]" $ do
25+
squishMap (\x -> [1, x, 3]) [2] `shouldBe` [1,2,3]
26+
it "squishMap (\\x -> \"WO \" ++ [x] ++ \" OT \") \"blah\"" $ do
27+
squishMap (\x -> "WO " ++ [x] ++ " OT ") "blah" `shouldBe` "WO b OT WO l OT WO a OT WO h OT "
28+
describe "Test myMaximumBy" $ do
29+
it "myMaximumBy (\\_ _ -> GT) [1..10]" $ do
30+
myMaximumBy (\_ _ -> GT) [1..10] `shouldBe` 1
31+
it "myMaximumBy (\\_ _ -> LT) [1..10]" $ do
32+
myMaximumBy (\_ _ -> LT) [1..10] `shouldBe` 10
33+
it "myMaximumBy compare [1..10]" $ do
34+
myMaximumBy compare [1..10] `shouldBe` 10
35+
describe "Test myMinimumBy" $ do
36+
it "myMinimumBy (\\_ _ -> GT) [1..10]" $ do
37+
myMinimumBy (\_ _ -> GT) [1..10] `shouldBe` 10
38+
it "myMinimumBy (\\_ _ -> LT) [1..10]" $ do
39+
myMinimumBy (\_ _ -> LT) [1..10] `shouldBe` 1
40+
it "myMinimumBy compare [1..10]" $ do
41+
myMinimumBy compare [1..10] `shouldBe` 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module FoldingLists.HowToWriteFoldFunctions.IntermissionExercisesSpec where
2+
3+
import Data.Time
4+
import Test.Hspec
5+
6+
import FoldingLists.HowToWriteFoldFunctions.IntermissionExercises
7+
8+
theDatabase :: [DatabaseItem]
9+
theDatabase =
10+
[ DbDate (UTCTime
11+
(fromGregorian 1911 5 1)
12+
(secondsToDiffTime 34123))
13+
, DbNumber 9001
14+
, DbString "Hello, world!"
15+
, DbDate (UTCTime
16+
(fromGregorian 1921 5 1)
17+
(secondsToDiffTime 34123))
18+
]
19+
20+
spec :: Spec
21+
spec = do
22+
describe "Test filterDbDate" $ do
23+
it "filterDbDate theDatabase" $ do
24+
let t1 = UTCTime (fromGregorian 1911 5 1) (secondsToDiffTime 34123)
25+
t2 = UTCTime (fromGregorian 1921 5 1) (secondsToDiffTime 34123)
26+
filterDbDate theDatabase `shouldBe` [t1, t2]
27+
describe "Test filterDbNumber" $ do
28+
it "filterDbNumber theDatabase" $ do
29+
filterDbNumber theDatabase `shouldBe` [9001]
30+
describe "Test mostRecent" $ do
31+
it "mostRecent theDatabase" $ do
32+
mostRecent theDatabase `shouldBe` UTCTime (fromGregorian 1921 5 1) (secondsToDiffTime 34123)
33+
describe "Test sumDb" $ do
34+
it "sumDb theDatabase" $ do
35+
sumDb theDatabase `shouldBe` 9001
36+
describe "Test avgDb" $ do
37+
it "avgDb theDatabase" $ do
38+
avgDb theDatabase `shouldBe` 9001
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module FoldingLists.Scans.ScansExercisesSpec where
2+
3+
import Test.Hspec
4+
import FoldingLists.Scans.ScansExercises
5+
6+
spec :: Spec
7+
spec = do
8+
describe "Test factorial" $ do
9+
it "take 5 factorial" $ do
10+
take 5 factorial `shouldBe` [1, 2, 6, 24, 120]

0 commit comments

Comments
 (0)