-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapter-20.hs
141 lines (102 loc) · 3.59 KB
/
chapter-20.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
-- I don't want any warnings as exercises will have some warnings.
{-# OPTIONS_GHC -w #-}
module Chapter_20 where
import Data.Monoid
-- Exercises: Library Functions
{-
Implement the functions in terms of foldMap or foldr from Foldable, then try
them out with multiple types that have Foldable instances.
-}
-- 1
-- This and the next one are nicer with foldMap, but foldr is fine too.
sumFoldMap :: (Foldable t, Num a) => t a -> a
sumFoldMap = getSum . foldMap Sum
sumFoldr :: (Foldable t, Num a) => t a -> a
sumFoldr = foldr (+) 0
-- 2
productFoldMap :: (Foldable t, Num a) => t a -> a
productFoldMap = getProduct . foldMap Product
productFoldr :: (Foldable t, Num a) => t a -> a
productFoldr = foldr (*) 1
--3
elemFoldMap :: (Foldable t, Eq a) => a -> t a -> Bool
elemFoldMap e = getAny . foldMap (\e' ->
if e == e'
then Any True
else Any False)
elemFoldr :: (Foldable t, Eq a) => a -> t a -> Bool
elemFoldr e = foldr (\e' acc -> (e == e') || acc) False
-- 4
minimumFoldr :: (Foldable t, Ord a) => t a -> Maybe a
minimumFoldr = foldr (\e acc ->
case acc of
Nothing -> Just e
Just e' -> Just $ min e e')
Nothing
-- TODO: Try this with `foldMap` as well: Try writing a monoid for `Num a => a`
-- which will return the minimum element on a1 <> a2.
-- 5
maximumFoldr :: (Foldable t, Ord a) => t a -> Maybe a
maximumFoldr = foldr (\e acc ->
case acc of
Nothing -> Just e
Just e' -> Just $ max e e')
Nothing
-- 6
nullFoldMap :: (Foldable t) => t a -> Bool
nullFoldMap = getAll . foldMap (const (All False))
nullFoldr :: (Foldable t) => t a -> Bool
nullFoldr = foldr (\_ _ -> False) True
-- 7
lengthFoldMap :: (Foldable t) => t a -> Int
lengthFoldMap = getSum . foldMap (const (Sum 1))
lengthFoldr :: (Foldable t) => t a -> Int
lengthFoldr = foldr (\_ acc -> acc + 1) 0
-- 8
-- Some say this is all Foldable amounts to.
toListFoldMap :: (Foldable t) => t a -> [a]
toListFoldMap = foldMap (: [])
toListFoldr :: (Foldable t) => t a -> [a]
toListFoldr = foldr (:) []
-- 9
-- Hint: use foldMap.
-- | Combine the elements
-- of a structure using a monoid.
foldFoldMap :: (Foldable t, Monoid m) => t m -> m
foldFoldMap = foldMap id
foldFoldr :: (Foldable t, Monoid m) => t m -> m
foldFoldr = foldr (<>) mempty
-- 10
-- Define foldMap in terms of foldr.
foldMapFoldr :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
foldMapFoldr f = foldr ((<>) . f) mempty
-- Reads better as: foldr (\e acc -> f e <> acc) mempty
-- Chapter Exercises
-- Write Foldable instances for the following datatypes.
-- 1
data Constant a b = Constant b
deriving (Eq, Show)
instance Foldable (Constant a) where
foldMap f (Constant b) = f b
-- 2
data Two a b = Two a b
deriving (Eq, Show)
instance Foldable (Two a) where
foldMap f (Two _ b) = f b
-- 3
data Three a b c = Three a b c
deriving (Eq, Show)
instance Foldable (Three a b) where
foldMap f (Three _ _ c) = f c
-- 4
data Three' a b = Three' a b b
deriving (Eq, Show)
instance Foldable (Three' a) where
foldMap f (Three' _ b b') = f b <> f b'
data Four' a b = Four' a b b b
deriving (Eq, Show)
instance Foldable (Four' a) where
foldMap f (Four' _ b b' b'') = f b <> f b' <> f b''
-- Thinking cap time. Write a filter function for Foldable types using foldMap.
filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a
filterF f = foldMap (\a -> if f a then pure a else mempty)