-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapter-12.hs
323 lines (245 loc) · 7.72 KB
/
chapter-12.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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
-- Chapter 12 exercises
import Data.Maybe
-- Chapter exercises
-- Determine the kinds
-- 1 -
{-
Given
id :: a -> a
What is the kind of a?
-}
-- Ans: *
-- 2
{-
r :: a -> f a
What are the kinds of a and f?
-}
-- Ans:
-- a :: *
-- f :: * -> *
-- String processing
-- 1
{-
WritearecursivefunctionnamedreplaceThewhichtakesatext/string, breaks it into
words and replaces each instance of “the” with “a”. It’s intended only to
replace exactly the word “the”. notThe is a suggested helper function for
accomplishing this.
-}
notThe :: String -> Maybe String
notThe "the" = Nothing
notThe "The" = Nothing
notThe str = Just str
replaceThe :: String -> String
replaceThe = unwords . go . words
where go [] = []
go (x : xs) = fromMaybe "a" (notThe x) : go xs
-- 2
{-
Write a recursive function that takes a text/string, breaks it into words, and
counts the number of instances of ”the” followed by a vowel-initial word.
-}
countTheBeforeVowel :: String -> Integer
countTheBeforeVowel = go . words
where go [] = 0
go ("the" : xs@( x@(v : _) : _)) =
if v `elem` "aeiouAEIOU" then 1 else 0 + go xs
go ("The" : xs@( x@(v : _) : _)) =
if v `elem` "aeiouAEIOU" then 1 else 0 + go xs
go (x : xs) = go xs
-- 3
{-
Return the number of letters that are vowels in a word.
Hint: it’s helpful to break this into steps. Add any helper functions
necessary to achieve your objectives.
a) Test for vowelhood
b) Return the vowels of a string
c) Count the number of elements returned
-}
countVowels :: String -> Integer
countVowels [] = 0
countVowels (x:xs)
| x `elem` "aeiouAEIOU" = 1 + countVowels xs
| otherwise = countVowels xs
-- Validate the word
{-
Use the Maybe type to write a function that counts the number of vowels in a
string and the number of consonants. If the number of vowels exceeds the number
of consonants, the function returns Nothing. In many human languages, vowels
rarely exceed the number of consonants so when they do, it may indicate the
input isn’t a word (that is, a valid input to your dataset):
-}
newtype Word' =
Word' String
deriving (Eq, Show)
mkWord :: String -> Maybe Word'
mkWord str =
let stripped = filter (/= ' ') str
countOfVowels = countVowels stripped
countOfConsonants = fromIntegral (length stripped) - countOfVowels
in
if countOfVowels <= countOfConsonants
then Just . Word' $ str
else Nothing
-- It’s only Natural
{-
You’ll be presented with a datatype to represent the natural numbers. The only
values representable with the naturals are whole numbers from zero to
infinity. Your task will be to implement functions to convert Naturals to
Integers and Integers to Naturals. The conversion from Naturals to Integers
won’t return Maybe because Integer is a strict superset of Natural. Any Natural
can be represented by an Integer, but the same is not true of any
Integer. Negative numbers are not valid natural numbers.
-}
data Nat =
Zero
| Succ Nat
deriving (Eq, Show)
natToInteger :: Nat -> Integer
natToInteger Zero = 0
natToInteger (Succ nat) = 1 + natToInteger nat
integerToNat :: Integer -> Maybe Nat
integerToNat num
| num < 0 = Nothing
| otherwise = Just $ go num
where go 0 = Zero
go num = Succ (go $ num - 1)
-- Small library for Maybe
-- 1 - Simple boolean checks for Maybe values.
isJust :: Maybe a -> Bool
isJust (Just a) = True
isJust _ = False
isNothing :: Maybe a -> Bool
isNothing = not . isJust
-- 2
{-
The following is the Maybe catamorphism. You can turn a Maybe value into
anything else with this.
-}
mayybee :: b -> (a -> b) -> Maybe a -> b
mayybee _ f (Just a) = f a
mayybee backup _ _ = backup
-- 3 - In case you just want to provide a fallback value.
fromMaybe :: a -> Maybe a -> a
fromMaybe a = mayybee a id
-- 4 - Converting between List and Maybe.
listToMaybe :: [a] -> Maybe a
listToMaybe [] = Nothing
listToMaybe (x:_) = Just x
maybeToList :: Maybe a -> [a]
maybeToList (Just a) = [a]
maybeToList Nothing = []
-- 5 - For when we want to drop the Nothing values from our list.
catMaybes :: [Maybe a] -> [a]
catMaybes = concatMap maybeToList
-- 6 - You’ll see this called “sequence” later.
flipMaybe :: [Maybe a] -> Maybe [a]
flipMaybe mxs =
if all isJust mxs
then Just . catMaybes $ mxs
else Nothing
-- Small library for Either
{-
Write each of the following functions. If more than one possible unique function
exists for the type, use common sense to determine what it should do.
-}
-- 1 -
{-
Try to eventually arrive at a solution that uses foldr, even if earlier
versions don’t use foldr.
-}
lefts' :: [Either a b] -> [a]
lefts' = foldr (\x acc ->
case x of
Left a -> a : acc
_ -> acc)
[]
-- 2 - Same as the last one. Use foldr eventually.
rights' :: [Either a b] -> [b]
rights' = foldr (\x acc -> case x of
Right b -> b : acc
_ -> acc)
[]
-- 3
partitionEithers' :: [Either a b] -> ([a], [b])
partitionEithers' = foldr (\x (as, bs) -> case x of
Left a -> (a : as, bs)
Right b -> (as, b : bs))
([], [])
-- 4
eitherMaybe' :: (b -> c) -> Either a b -> Maybe c
eitherMaybe' _ (Left _) = Nothing
eitherMaybe' f (Right b) = Just . f $ b
-- 5 - This is a general catamorphism for Either values.
either' :: (a -> c) -> (b -> c) -> Either a b -> c
either' fac _ (Left a) = fac a
either' _ fbc (Right b) = fbc b
-- 6 - Same as before, but use the either' function you just wrote.
eitherMaybe'' :: (b -> c) -> Either a b -> Maybe c
eitherMaybe'' fbc (Left _) = Nothing
eitherMaybe'' fbc (Right b) = Just . fbc $ b
-- Write your own iterate and unfoldr
-- 1
{-
Write the function myIterate using direct recursion. Compare the behavior with
the built-in iterate to gauge correctness. Do not look at the source or any
examples of iterate so that you are forced to do this yourself.
-}
myIterate :: (a -> a) -> a -> [a]
myIterate f a = a : myIterate f (f a)
-- 2
{-
Write the function myUnfoldr using direct recursion. Compare with the built-in
unfoldr to check your implementation. Again, don’t look at implementations of
unfoldr so that you figure it out yourself.
-}
myUnfoldr :: (b -> Maybe (a, b)) -> b -> [a]
myUnfoldr f b =
case f b of
Just (a, b) -> a : myUnfoldr f b
Nothing -> []
-- 3
{-
Rewrite myIterate into betterIterate using myUnfoldr. A hint — we used unfoldr
to produce the same results as iterate earlier. Do this with different functions
and see if you can abstract the structure out.
-}
betterIterate :: (a -> a) -> a -> [a]
betterIterate f = myUnfoldr (\x -> Just (x, f x))
-- Finally something other than a list!
{-
Given the BinaryTree from last chapter, complete the following exercises. Here’s
that datatype again:
-}
data BinaryTree a =
Leaf
| Node (BinaryTree a) a (BinaryTree a)
deriving (Eq, Ord, Show)
-- 1 - Write unfold for BinaryTree.
unfold :: (a -> Maybe (a, b, a)) -> a -> BinaryTree b
unfold f a =
case f a of
Just (l, b, r) -> Node (unfold f l) b (unfold f r)
Nothing -> Leaf
-- (Not in the exercise) Code to generate a binary tree with root 5 which goes
-- to left till 0 and to the right till 10
unfold (\x ->
if x == 5
then Just (x - 1, x, x + 1)
else
if x < 5 && x > 0
then Just (x - 1, x, 0)
else
if x > 5 && x < 10
then Just (0, x, x + 1)
else Nothing)
5
-- 2 - Make a tree builder.
{-
Using the unfold function you’ve made for BinaryTree, write the following
function:
-}
treeBuild :: Integer -> BinaryTree Integer
treeBuild n =
unfold (\x -> if x < n
then Just (x + 1, x, x + 1)
else Nothing) 0