-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlecture-02.lhs
351 lines (215 loc) · 8.68 KB
/
lecture-02.lhs
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
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
University of Zagreb
Faculty of Electrical Engineering and Computing
PROGRAMMING IN HASKELL
Academic Year 2017/2018
LECTURE 2: Lists (cont.) and tuples
v1.0
(c) 2017 Jan Šnajder
==============================================================================
> import Data.Char
> import Data.List
=== LISTS (cont.) ============================================================
Lists cannot be heterogeneous (contain elements of different types). E.g., we
cannot have: [1,'a',3].
Replicate, cycle, and repeat:
> l9 = repeat 'a'
> l10 = cycle [1,2,3]
> l11 = replicate 10 'a'
How to implement 'replicate' with repeat?
> replicate' n x = take n $ repeat x
List intervals:
> l12 = [1..100]
> l13 = [1,3..999]
> l14 = take 10 [1,3..100]
> l15 = [1..]
> l16 = ['a'..'z']
Laziness in action:
> l17 = take 10 [1..]
> l18 = head [1..]
What's going on here?:
> l19 = tail [1..]
> n = length [1..]
A list without its first and last element:
> trim l = tail (init l)
> trim' l = init $ tail l
> blanks = repeat ' '
> padTo10 s = s ++ take (10 - length s) blanks
Be careful with this:
> l20 = head []
Lists of lists:
> l21 = [[1,2,3],[4,5,6],[7,8,9,10]]
> l22 = ["red","green","blue"]
Again, remember that lists cannot be heterogenous, thus we cannot have
[1,2,[3,4]] nor ["red",'a'].
Concatenating list of sublists:
> l23 = concat l21
Minimum and maximum of a list:
> m1 = minimum [4, 1, 2, 3]
> m2 = maximum "Haskell for the win!"
Looking up elements from a list:
> e1 = [1,3..100] !! 17
> e2 = l21 !! 1 !! 2
Our own implementation of 'chr':
> intToChar i = ['A'..] !! (i - 65)
What happens if i < 65? Let's fix this:
> intToChar' i | i >= 65 = ['A'..] !! (i - 65)
> | otherwise = error "Index should be at least 65"
Logical operation on lists:
> r1 = and [True,True,False]
> r2 = or [True,True,False]
Removing duplicates with 'nub':
> l24 = nub [1, 2, 3, 1, 1, 2]
> l25 = nub "Give me every letter only once!"
Sorting a list:
> l26 = sort [1,4,5,6,1,2]
> l27 = sort "Alphabet"
Checking list membership: 'elem' and 'notElem':
> hasA xs = 'a' `elem` xs
Function 'null' returns True if the list is empty, otherwise it returns False.
> isEmpty = null l27
We now have three ways at our disposal to check whether a list is empty:
(1) length xs == 0
(2) xs == []
(3) null xs
Which one should you use? You should definitively use (3). Approach (1) won't
work for infinite list. Approach (2) is more restrictive than (3), because it
won't work for all list types (why this is so will be clear after Lecture 3).
=== EXERCISE 1 ===============================================================
1.1.
- Define a function that returns a list without the first three elements and
last three elements.
1.2.
- Define a function 'initals s1 s2' that takes a person's name and a surname
as input and returns a string consisting of person's initials.
initials "James" "Bond" => "J. B."
1.3.
- Define a function that concatenates two strings, so that the longest string
always comes first.
1.4.
- Define a function 'safeHead' that returns an empty list if 'l' is an empty
list, otherwise it returns its first element wrapped inside a singleton list.
1.5.
- Define a function 'hasDuplicates' that checks whether a list contains
duplicate elements (use 'nub').
=== LIST COMPREHENSIONS ======================================================
> doubles = [x*2 | x <- [1..10]]
> sums1 = [x + y | x <- [1..10], y <- [1..10]]
> sums2 = [x + y | x <- [1..10], y <- [1..10], x < y]
> sums3 = [x + y | x <- [1..10], y <- [1..10], x < y, odd x || even y]
List of sublist lengths:
> lengths xss = [length xs | xs <- xss]
> totalLength xss = sum $ lengths xss
Combining strings:
> food = [s1 ++ " " ++ s2 |
> s1 <- ["cold", "hot", "fresh"],
> s2 <- ["cake", "strudel", "salad"]]
Since strings are actually lists of characters, we can do list comprehensions
with strings:
> codes = [ [c1,c2] | c1 <- "abc", c2 <- "123"]
> caesarCode s = [succ c | c <- s, c /= ' ']
> onlyDigits s = [c | c <- s, isDigit c]
> upperCase s = [toUpper c | c <- s]
=== EXERCISE 2 ===============================================================
2.1
- Define 'doublesFromTo a b' that generates a sequence [a*2, (a+1)*2,... b*2]
and also works when b<a.
2.2.
- Redefine 'ceasarCode n xs' so that it shifts all letters a specified number
of positions 'n', converts all input to lowercase, and ensures that letters
remain within the ['a'..'z'] interval.
==============================================================================
Breaking up a string into tokens:
> ws = words "I think we agree, the past is over."
Breaking up a string into lines:
> ls = lines "First line\nSecond line"
Concatenating lines into a single string:
> stream = unlines ls
Filtering words with initial uppercase letter:
> capitalized s = [w | w <- words s, isUpper $ head w]
> camelCase s = concat [toUpper (head w) : tail w | w <- words s]
Or, more succinctly, using pattern matching:
> camelCase' s = concat [toUpper h : t | (h:t) <- words s]
=== EXERCISE 3 ===============================================================
3.1.
- Define 'letterCount' that computes the total number of letters in a string,
thereby ignoring the whitespaces and all words shorter than three letters.
You can use 'totalLength'.
3.2
- Redefine 'isPalindrome' so that it's case insensitive and works correctly
for strings that contain whitespaces.
3.3.
- Define 'flipp xss' that takes a list of lists, reverts each individual list,
and concatenates all of them, but in the reverse order.
flip ["water","is","warm"] -> "mrawsiretaw"
=== TUPLES ===================================================================
> pair1 = (1, 2)
> pair2 = ("Vatroslav", "Lisinski")
> triplet1 = (10, 1, 8)
> triplet2 = ("Vatroslav", "Lisinski", 1819)
> e3 = pair1 == (1, 2)
What do we get if we type in 'pair1 == pair2' ?
Assigning values to tuples:
> (a,b) = (1,2)
Extract of the first and the second element of a tuple, respectively:
> p = fst (5,6)
> q = snd (5,6)
List of pairs:
> pairs = [(1,2),(3,4),(5,6)]
Pairs of numbers from 1 to 100:
> pairsUpTo100 = [(x,y) | x <- [0..100], y <- [0..100]]
Pairs of numbers that sum up to 100:
> pairsSumTo100 = [(x,y) | x <- [0..100], y <- [0..100], x + y == 100 ]
Integer lengths of triangle sides that satisfy the Pythagorean theorem
(Pythagorean triplets):
> pythagoreanTriplets =
> [(a,b,c) | a <- [1..10], b <- [1..10], c <- [1..10], a^2 + b^2 == c^2]
Can be optimized:
> pythagoreanTriplets' =
> [(a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a], a^2 + b^2 == c^2]
'zip' function:
> pairs2 = zip [1,2,3] "abc"
> pairs3 = zip [1,2,3,4] "abc"
> pairs4 = zip [1..] "abc"
> pairs5 = zip [1..100] [2..100]
=== EXERCISE 4 ===============================================================
4.1.
- Define 'inCircle r x y' that returns the coordinates of all points within
the ([-10..10],[-10..10]) interval that fall inside a circle of radius
'r' with center '(x,y)'.
- Redefine the function so that it takes the resolution of the grid as an
additional argument.
4.2.
- Define 'steps xs' that, given a list xs=[x1,x2,..], generates the pairs
[(x1,x2),(x2,x3),...]. Hint: have a look at 'pairs5'.
==============================================================================
Indexing elements of a list:
> index xs = zip [1..] xs
Filtering every second list element:
> evenElems xs = [ snd ix | ix <- index xs, even (fst ix)]
The same thing, but using pattern matching:
> evenElems' xs = [ x | (i,x) <- index xs, even i]
Zip3:
> triplets2 = zip3 [0..10] ['A'..] [100..]
=== EXERCISE 5 ===============================================================
5.1.
- Define 'indices x xs' that returns the indices of element 'x' in list 'xs'
(if 'x' appears multiple times, there will be a number of such indices).
indices 'a' "alphabet" => [0, 4]
5.2.
- Define 'showLineNumbers s' that prefixes all lines from string 's' with a
line number.
showLineNumbers "first line\nsecond line" => "1 first line\n2 second line\n"
5.3.
- Define 'haveAlignment xs ys' that returns 'True' if 'xs' and 'ys' have
any identical elements that are aligned (appear at the same position in
both lists).
- Define 'common xs ys' that returns the aligned subsequences.
haveAlignment "water" "fire" => True
common "witer" "fire" => "ie"
=== NEXT =====================================================================
So far we have deliberately avoided talking about types of values and
functions. Because Haskell is a strongly and statically typed language, we
cannot postpone this any longer. In the next lecture, we'll look into types
and type inference system of Haskell.
To prepare, you may (but need not to) read Chapter 3 of LYH:
http://learnyouahaskell.com/types-and-typeclasses