work in progress
[lambda.git] / exercises / _assignment5.mdwn
1 Assignment 5
2
3 ω
4 Ω
5 λ
6 Λ
7
8 α
9 β
10
11
12
13 ## Option / Maybe Types ##
14
15 You've already defined and worked with `map` as a function on lists. Now we're going to work instead with the type OCaml defines like this:
16
17     type ('a) option = None | Some of 'a
18
19 and Haskell defines like this:
20
21     data Maybe a = Nothing | Just a
22
23 That is, instances of this type are either some `'a` (this can be any type), wrapped up in a `Some` or `Just` box, or they are a separate value representing a failure. This is sort of like working with a list guaranteed to have a length ≤ 1.
24
25 In one of the homework sessions, Chris posed the challenge: you know those dividers they use in checkout lines to separate your purchases from the next person's? What if you wanted to buy one of those dividers? How could they tell whether it belonged to your purchases or was separating them from others?
26
27 The OCaml and Haskell solution is to use not supermarket dividers but instead those gray bins from airport security. If you want to buy something, it goes into a bin. (OCaml's `Some`, Haskell's `Just`). If you want to separate your stuff from the next person, you send an empty bin (OCaml's `None`, Haskell's `Nothing`). If you happen to be buying a bin, OK, you put that into a bin. In OCaml it'd be `Some None` (or `Some (Some stuff)` if the bin you're buying itself contains some stuff); in Haskell `Just Nothing`. We won't confuse a bin that contains a bin with an empty bin. (Not even if the contained bin is itself empty.)
28
29 1.  Your first problem is to write a `maybe_map` function for these types. Here is the type of the function you should write:
30
31         (* OCaml *)
32         maybe_map : ('a -> 'b) -> ('a) option -> ('b) option
33
34         -- Haskell
35         maybe_map :: (a -> b) -> Maybe a -> Maybe b
36
37     If your `maybe_map` function is given a `None` or `Nothing` as its second argument, that should be what it returns. Otherwise, it should apply the function it got as its first argument to the contents of the `Some` or `Just` bin that it got as its second, and return the result, wrapped back up in a `Some` or `Just`.
38
39     One way to extract the contents of a option or Maybe value is to pattern match on that value, as you did with lists. In OCaml:
40
41         match x with
42         | None -> ...
43         | Some y -> ...
44
45     In Haskell:
46
47         case x of {
48           Nothing -> ...;
49           Just y -> ...
50         }
51
52     Some other tips: In OCaml you write recursive functions using `let rec`, in Haskell you just use `let` (it's already assumed to be recursive). In OCaml when you finish typing something and want the interpreter to parse it, check and display its type, and evaluate it, type `;;` and then return. You may want to review the [[Rosetta pages here]] and also read some of the tutorials we linked to [[for OCaml]] or [[for Haskell]]. [WHERE]
53
54
55 2.  Next write a `maybe_map2` function. Its type should be:
56
57         (* OCaml *)
58         maybe_map2 ('a -> 'b -> 'c) -> ('a) option -> ('b) option -> ('c) option
59
60         -- Haskell
61         maybe_map2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
62
63
64
65 ## Color Trees ##
66
67 (The questions on Color and Search Trees are adapted from homeworks in Chapters 1 and 2 of Friedman and Wand, *Essentials of Programming Languages*.)
68
69 Here are type definitions for one kind of binary tree:
70
71     (* OCaml *)
72     type color = Red | Green | Blue | ... (* you can add as many as you like *)
73     type ('a) color_tree = Leaf of 'a | Branch of 'a color_tree * color * 'a color_tree
74
75     -- Haskell
76     data Color = Red | Green | Blue | ...  deriving (Eq, Show)
77     data Color_tree a = Leaf a | Branch (Color_tree a) Color (Color_tree a)  deriving (Show)
78
79 These trees always have colors labeling their inner branching nodes, and will have elements of some type 'a labeling their leaves. `(int) color_tree`s will have `int`s there, `(bool) color_tree`s will have `bool`s there, and so on. The `deriving (Eq, Show)` part at the end of the Haskell declarations is boilerplate to tell Haskell you want to be able to compare the colors for equality, and also that you want the Haskell interpreter to display colors and lists to you when they are the result of evaluating an expression.
80
81 Here's how you create an instance of such a tree:
82
83     (* OCaml *)
84     let t1 = Branch (Leaf 1, Red, Branch (Leaf 2, Green, Leaf 0))
85
86     -- Haskell
87     let t1 = Branch (Leaf 1) Red (Branch (Leaf 2) Green (Leaf 0))
88
89 Here's how you pattern match such a tree, binding variables to its components:
90
91     (* OCaml *)
92     match t with
93     | Leaf n -> false
94     | Branch (_, c, _) -> c = Red
95
96     -- Haskell
97     case t of {
98       Leaf n -> False;
99       Branch _ c _ -> c == Red
100     }
101
102 These expressions query whether `t` is a branching `color_tree` (not a leaf) whose root is labeled `Red`.
103
104 Choose one of these languages and write the following functions.
105
106
107 3.  Define a function `tree_map` whose type is (as shown by OCaml): `('a -> 'b) -> ('a) color_tree -> ('b) color_tree`. It expects a function `f` and an `('a) color_tree`, and returns a new tree with the same structure and inner branch labels as the original, but with all of its leaves now having had `f` applied to their original value. So for example, `map (2*) t1` would return `t1` with all of its leaf values doubled.
108
109 4.  Define a function `tree_foldleft` that accepts an argument `g : 'z -> 'a -> 'z` and a seed value `z : 'z` and a tree  `t : ('a) color_tree`, and returns the result of applying `g` first to `z` and `t`'s leftmost leaf, and then applying `g` to *that result* and `t`'s second-leftmost leaf, and so on, all the way across `t`'s fringe.
110
111 5.  How would you use the function defined in problem 4 (the previous problem) to sum up the values labeling the leaves of an `(int) color_tree`?
112
113 6.  How would you use the function defined in problem 4 to enumerate a tree's fringe? (Don't worry about whether it comes out left-to-right or right-to-left.)
114
115 7.  How would you use the function defined in problem 4 to make a copy of a tree with the same structure and inner node labels, but where the leftmost leaf is now labeled `0`, the second-leftmost leaf is now labeled `1`, and so on.
116
117 8.  (More challenging.) Write a recursive function that makes a copy of a tree with the same structure and inner node labels, but replaces each leaf label with the int that reports how many of that leaf's ancestors are labeled `Red`. For example, if we give your function a tree:
118
119     <pre>
120         Red
121         / \
122       Blue \
123       / \  Green
124      a   b  / \
125            c   Red
126                / \
127               d   e
128     </pre>
129
130     (for any leaf values `a` through `e`), it should return:
131
132     <pre>
133         Red
134         / \
135       Blue \
136       / \  Green
137      1   1  / \
138            1   Red
139                / \
140               2   2
141     </pre>
142
143 9.  (More challenging.) Assume you have a `color_tree` whose leaves are labeled with `int`s (which might be negative). For this problem, assume also that the the same color never labels multiple inner nodes. Write a recursive function that reports which color has the greatest score when you sum up all the values of its descendent leaves. Since some leaves may have negative values, the answer won't always be the color at the tree root. In the case of ties, you can return whichever of the highest scoring colors you like.
144
145
146 ## Search Tree ##
147
148 (More challenging.) For the next problem, assume the following type definition:
149
150     (* OCaml *)
151     type search_tree = Nil | Inner of search_tree * int * search_tree
152
153     -- Haskell
154     data Search_tree = Nil | Inner Search_tree Int Search_tree  deriving (Show)
155
156 That is, its leaves have no labels and its inner nodes are labeled with `int`s. Additionally, assume that all the `int`s in nodes descending to the left from a given node will be less than the `int` of that parent node, and all the `int`s in nodes descending to the right will be greater. We can't straightforwardly specify this constraint in OCaml's or Haskell's type definitions. We just have to be sure to maintain it by hand.
157
158 10. Write a function `search_for` with the following type, as displayed by OCaml:
159
160         type direction = Left | Right
161         search_for : int -> search_tree -> direction list option
162
163     Haskell would say instead:
164
165         data Direction = Left | Right  deriving (Eq, Show)
166         search_for :: Int -> Search_tree -> Maybe [Direction]
167
168     Your function should search through the tree for the specified `int`. If it's never found, it should return the value OCaml calls `None` and Haskell calls `Nothing`. If it finds the `int` right at the root of the search_tree, it should return the value OCaml calls `Some []` and Haskell calls `Just []`. If it finds the `int` by first going down the left branch from the tree root, and then going right twice, it should return `Some [Left; Right; Right]` or `Just [Left, Right, Right]`.
169
170
171 ## More Map2s ##
172
173 Above, you defined `maybe_map2` [WHERE]. Before we encountered `map2` for lists. There are in fact several different approaches to mapping two lists together.
174
175 11. One approach is to apply the supplied function to the first element of each list, and then to the second element of each list, and so on, until the lists are exhausted. If the lists are of different lengths, you might stop with the shortest, or you might raise an error. Different implementations make different choices about that. Let's call this function:
176
177         (* OCaml *)
178         map2_zip : ('a -> 'b -> 'c) -> ('a) list -> ('b) list -> ('c) list
179
180     Write a recursive function that implements this, in Haskell or OCaml. Let's say you can stop when the shorter list runs out, if they're of different lengths. (OCaml and Haskell each already have functions in their standard libraries that do this. This also corresponds to what you can write as a list comprehension in Haskell like this:
181
182         :set -XParallelListComp
183         [ f x y | x <- xs | y <- ys ]
184
185     But we want you to write this function from scratch.)
186
187 12. What is the relation between the function you just wrote, and the `maybe_map2` function you wrote for an earlier problem?
188
189 13. Another strategy is to take the *cross product* of the two lists. If the function:
190
191         (* OCaml *)
192         map2_cross : ('a -> 'b -> 'c) -> ('a) list -> ('b) list -> ('c) list list
193
194     is applied to the arguments `f`, `[x0, x1, x2]`, and `[y0, y1]`, then the result should be: `[[f x0 y0, f x0 y1], [f x1 y0, f x1 y1], [f x2 y0, f x2 y1]]`. Write this function.
195
196 A similar choice between "zipping" and "crossing" could be made when `map2`-ing two trees. For example, the trees:
197
198 <pre>
199     0       5
200    / \     / \
201   1   2   6   7
202  / \         / \
203  3  4        8  9
204 </pre>
205
206 could be "zipped" like this (ignoring any parts of branches on the one tree that extend farther than the corresponding branch on the other):
207
208 <pre>
209    f 0 5
210    /    \
211 f 1 6  f 2 7
212 </pre>
213
214 14. You can try defining that if you like, for extra credit.
215
216 "Crossing" the trees would instead add copies of the second tree as subtrees replacing each leaf of the original tree, with the leaves of that larger tree labeled with `f` applied to `3` and `6`, then `f` applied to `3` and `8`, and so on across the fringe of the second tree; then beginning again (in the subtree that replaces the `4` leaf) with `f` applied to `4` and `6`, and so on.
217
218 *   In all the plain `map` functions, whether for lists, or for option/Maybes, or for trees, the structure of the result exactly matched the structure of the argument.
219
220 [LOOKUP in APPLICATIVE]
221
222 *   In the `map2` functions, whether for lists or for option/Maybes or for trees, and whether done in the "zipping" style or in the "crossing" style, the structure of the result may be a bit different from the structure of the arguments. But the *structure* of the arguments is enough to determine the structure of the result; you don't have to look at the specific list elements or labels on a tree's leaves or nodes to know what the *structure* of the result will be.
223
224 *   We can imagine more radical transformations, where the structure of the result *does* depend on what specific elements the original structure(s) had. For example, what if we had to transform a tree by turning every leaf into a subtree that contained all of those leaf's prime factors. Or consider our problem from last week [WHERE] where you converted `[3, 2, 0, 1]` not into `[[3,3,3], [2,2], [], [1]]` --- which still has the same structure, that is length, as the original --- but rather into `[3, 3, 3, 2, 2, 1]` --- which doesn't.
225
226 These three levels of how radical a transformation you are making to a structure, and the parallels between the transformations to lists, to option/Maybes, and to trees, will be ideas we build on in coming weeks.
227
228
229
230
231
232 ## Untyped Lambda Terms ##
233
234 In OCaml, you can define some datatypes that represent terms in the untyped Lambda Calculus like this:
235
236     type identifier = string
237     type lambda_term = Var of identifier | Abstract of identifier * _____ | App of _____ ;;
238
239 We've left some gaps.
240
241 In Haskell, you'd define it instead like this:
242
243     type Identifier = String
244     data Lambda_term = Var Identifier | Abstract Identifier _____ | App ________
245
246 15. Again, we've left some gaps. Choose one of these languages and fill in the gaps to complete the definition.
247
248 16. Write a function `occurs_free` that has the following type:
249
250     occurs_free : identifier -> lambda_term -> bool
251
252 That's how OCaml would show it. Haskell would use double colons `::` instead, and would also capitalize all the type names. Your function should tell us whether the supplied identifier ever occurs free in the supplied `lambda_term`.
253
254
255
256
257 ## Encoding Booleans, Church numerals, and Right-Fold Lists in System F ##
258
259 (These questions are adapted from web materials by Umut Acar. See
260 <http://www.mpi-sws.org/~umut/>.)
261
262
263 (For the System F questions, you can either download and compile Pierce's evaluator for system F to test your work [WHERE], or work on paper.)
264
265
266
267
268 Let's think about the encodings of booleans, numerals and lists in System F,
269 and get data-structures with the same form working in OCaml or Haskell. (Of course, OCaml and Haskell
270 have *native* versions of these datas-structures: OCaml's `true`, `1`, and `[1;2;3]`.
271 But the point of our exercise requires that we ignore those.)
272
273 Recall from class System F, or the polymorphic λ-calculus, with this grammar:
274
275     types ::= type_constants | α ... | type1 -> type2 | ∀α. type
276     expressions ::= x ... | λx:type. expr | expr1 expr2 | Λα. expr | expr [type]
277
278 The boolean type, and its two values, may be encoded as follows:
279
280     bool ≡ ∀α. α -> α -> α
281     true ≡ Λα. λy:α. λn:α. y
282     false ≡ Λα. λy:α. λn:α. n
283
284 It's used like this:
285
286     b [T] res1 res2
287
288 where `b` is a boolean value, and `T` is the shared type of `res1` and `res2`.
289
290
291 17. How should we implement the following terms? Note that the result
292 of applying them to the appropriate arguments should also give us a term of
293 type `bool`.
294
295     (a) the term `not` that takes an argument of type `bool` and computes its negation
296     (b) the term `and` that takes two arguments of type `bool` and computes their conjunction
297     (c) the term `or` that takes two arguments of type `bool` and computes their disjunction
298
299 The type `nat` (for "natural number") may be encoded as follows:
300
301     nat ≡ ∀α. (α -> α) -> α -> α
302     zero ≡ Λα. λs:α -> α. λz:α. z
303     succ ≡ λn:nat. Λα. λs:α -> α. λz:α. s (n [α] s z)
304
305 A number `n` is defined by what it can do, which is to compute a function iterated n
306 times. In the polymorphic encoding above, the result of that iteration can be
307 any type `α`, as long as you have a function `s : α -> α` and a base element `z : α`.
308
309 18. Get booleans and Church numbers working in OCaml or Haskell,
310 including versions of `bool`, `true`, `false`, `zero`, `zero?` (though this is not a legal function name in either of those languages, use something else), `succ`, and `pred`.
311 It's especially useful to do a version of `pred`, starting with one of the (untyped) versions available in the lambda library accessible from the main wiki page. [WHERE]  The point of the exercise is to do these things on your own, so avoid using the built-in OCaml or Haskell booleans and integers.
312
313 Consider the following list type, specified using OCaml or Haskell datatypes:
314
315     (* OCaml *)
316     type ('a) my_list = Nil | Cons of 'a * 'a my_list
317
318      -- Haskell
319      data My_list a = Nil | Cons a (My_list a)
320
321 We can encode that type into System F as a right-fold, just as we did in the untyped Lambda Calculus, like this:
322
323     list_T ≡ ∀α. (T -> α -> α) -> α -> α
324     nil_T ≡ Λα. λc:T -> α -> α. λn:α. n
325     cons_T ≡ λx:T. λxs:list_T. Λα. λc:T -> α -> α. λn:α. c x (xs [α] c n)
326
327 A more general polymorphic list type is:
328
329     list ≡ ∀β. ∀α. (β -> α -> α) -> α -> α
330
331 As with nats, the natural recursion is built into our encoding of this datatype. So we can write functions like `map`:
332
333     map : (S -> T) -> list_S -> list_T
334
335 <!--
336     = λf:S -> T. λxs:list. xs [S] [list [T]] (λx:S. λys:list [T]. cons [T] (f x) ys) (nil [T])
337 -->
338
339 19. Convert this list encoding and the `map` function to OCaml or Haskell. Call it `sysf_list`, `sysf_nil` and so on, to avoid collision with the names for native lists in these languages.
340
341 20. Also give us the type and definition for a `sysf_head` function. Think about what value to give back if the argument is the empty list.  Ultimately, we might want to make use of the option/Maybe technique explored in questions 1--2, but for this assignment, just pick a strategy, no matter how clunky. 
342
343 Be sure to test your proposals with simple lists. (You'll have to `sysf_cons` up a few sample lists yourself; don't expect OCaml or Haskell to magically translate between their native lists and the ones you've just defined.)
344
345
346 21. Modify the implementation of the predecessor function [[given in the class notes|topics/week5_system_f]] [WHERE] to implement a `sysf_tail` function for your lists.
347
348
349
350
351
352
353
354
355 ## More on Types ##
356
357 22.  Recall that the S combinator is given by `\f g x. f x (g x)`. Give two different typings for this term in OCaml. To get you started, here's one typing for **K**:
358
359         # let k (y:'a) (n:'b) = y;;
360         val k : 'a -> 'b -> 'a = [fun]
361         # k 1 true;;
362         - : int = 1
363
364     If you can't understand how one term can have several types, recall our discussion in this week's notes [WHERE] of "principal types".
365
366
367
368
369 ## Evaluation Order ##
370
371 Do these last three problems specifically with OCaml in mind, not Haskell. Analogues of the questions exist in Haskell, but because the default evaluation rules for these languages are different, it's too complicated to look at how these questions should be translated into the Haskell setting.
372
373
374 23.  Which of the following expressions is well-typed in OCaml? For those that are, give the type of the expression as a whole. For those that are not, why not?
375
376         let rec f x = f x;;
377
378         let rec f x = f f;;
379
380         let rec f x = f x in f f;;
381
382         let rec f x = f x in f ();;
383
384         let rec f () = f f;;
385
386         let rec f () = f ();;
387
388         let rec f () = f () in f f;;
389
390         let rec f () = f () in f ();;
391
392 24.  Throughout this problem, assume that we have:
393
394         let rec blackhole x = blackhole x;;
395
396     <!-- Haskell could say: `let blackhole = \x -> fix (\f -> f)` -->
397
398     All of the following are well-typed. Which ones terminate?  What are the generalizations?
399
400         blackhole;;
401
402         blackhole ();;
403
404         fun () -> blackhole ();;
405
406         (fun () -> blackhole ()) ();;
407
408         if true then blackhole else blackhole;;
409
410         if false then blackhole else blackhole;;
411
412         if true then blackhole else blackhole ();;
413
414         if false then blackhole else blackhole ();;
415
416         if true then blackhole () else blackhole;;
417
418         if false then blackhole () else blackhole;;
419
420         if true then blackhole () else blackhole ();;
421
422         if false then blackhole () else blackhole ();;
423
424         let _ = blackhole in 2;;
425
426         let _ = blackhole () in 2;;
427
428 25.  This problem is to think about how to control order of evaluation.
429 The following expression is an attempt to make explicit the
430 behavior of `if ... then ... else ...` explored in the previous question.
431 The idea is to define an `if ... then ... else ...` expression using
432 other expression types.  So assume that `yes` is any (possibly complex) OCaml expression,
433 and `no` is any other OCaml expression (of the same type as `yes`!),
434 and that `bool` is any boolean expression.  Then we can try the following:
435 `if bool then yes else no` should be equivalent to
436
437         let b = bool in
438         let y = yes in
439         let n = no in
440         match b with true -> y | false -> n
441
442     This almost works.  For instance,
443
444         if true then 1 else 2;;
445
446     evaluates to 1, and
447
448         let b = true in let y = 1 in let n = 2 in
449         match b with true -> y | false -> n;;
450
451     also evaluates to 1.  Likewise,
452
453         if false then 1 else 2;;
454
455     and
456
457         let b = false in let y = 1 in let n = 2 in
458         match b with true -> y | false -> n;;
459
460     both evaluate to 2.
461
462     However,
463
464         let rec blackhole x = blackhole x in
465         if true then blackhole else blackhole ();;
466
467     terminates, but
468
469         let rec blackhole x = blackhole x in
470         let b = true in
471         let y = blackhole in
472         let n = blackhole () in
473         match b with true -> y | false -> n;;
474
475     does not terminate.  Incidentally, using the shorter `match bool with true -> yes | false -> no;;` rather than the longer `let b = bool ... in match b with ...` *would* work as we desire. But your assignment is to control the evaluation order without using the special evaluation order properties of OCaml's native `if` or of its `match`. That is, you must keep the `let b = ... in match b with ...` structure in your answer, though you are allowed to adjust what `b`, `y`, and `n` get assigned to.
476
477     [[hints/assignment 5 hint 1]] WHERE