7.4.0.4

Extra Exercises My First Turnstile Language

Jesse Tov

There are no dependencies between these exercises, so you can attempt any of them in any order.

Exercise 48. Extend the syntax of def to support this convenient sugar for defining functions:

(def (- [x Int] [y Int])
  (+ x (* y -1)))

Don’t forget to test!

Exercise 49. Suppose you want to curry a function of type (-> Int Int Int), turning it into a function of type (-> Int (-> Int Int)). If you’ve implemented the rules from this morning for both annotated and unannotated λs, then writing it either of these two ways should work:

> (λ ([f (-> Int Int Int)])
         (λ ([x Int])
           (λ ([y Int])
             (f x y))))

#<procedure>

> (ann (λ (f) (λ (x) (λ (y) (f x y))))
       (-> (-> Int Int Int) (-> Int (-> Int Int))))

#<procedure>

However, this “in-between” way probably doesn’t:

> (ann (λ ([f (-> Int Int Int)])
         (λ (x) (λ (y) (f x y))))
       (-> (-> Int Int Int) (-> Int (-> Int Int))))

eval:14.0: λ: no expected type, add annotations

  at: (λ (x) (λ (y) (f x y)))

  in: (λ (x) (λ (y) (f x y)))

  parsing context:

   while parsing has-expected-type

    term: (λ (x) (λ (y) (f x y)))

    location: eval:14.0

Why not? Can you fix it?

Exercise 50. Racket’s let* is like let, except that each local variable that it binds is in scope for subsequent bindings:

> (let* ([x 3]
         [y (add1 x)])
    y)

4

> (let ([x 3]
        [y (add1 x)])
    y)

x: undefined;

 cannot reference an identifier before its definition

  module: 'program

Extend your typed langauge with a let* form.

Hint: Implementing let* using pattern repetition (...) is quite difficult; use recursion.

Exercise 51. Racket’s let form can have a name:

(let name
  ([var rhs] ...)
  body ...)

This binds name locally inside the let to a function that re-evaluates the let while binding the variables var ... to the function’s arguments instead of to rhs .... As syntatic sugar, you might think of it as being equivalent to a combination of letrec and λ:

(letrec
    ([name (λ (var ...) body ...)])
  (name rhs ...))

Unfortunately, that translation doesn’t work in our typed language, because 1) we don’t have letrec, and 2) even if we did, it would require type annotations that the original let form doesn’t have.

To type named let directly, you will need a type annotation. Figure out what type annotation you need, choose a syntax for it, and extend your typed syntax for let to handle it. Then make sure your extension hasn’t broken anonymous let.