Logo EPFL
LAMP
Ecole Polytechnique Fédérale de Lausanne
Written Assignment
English only

Written Assignment - Solutions

Arithmetic Expressions

Task 1) Arithmetic Expressions with plus

plus succ(nv1) nv2 → plus nv'1 succ(nv2)
(E-Plus1)
t1 → t'1
plus t1 t2 → plus t'1 t2
(E-Plus-C1)
plus zero nv2 → nv2
(E-Plus2)
t2 → t'2
plus nv1 t2 → plus nv'1 t2'
(E-Plus-C2)
equal succ(nv1) succ(nv2) → equal nv1 nv2
(E-EqualSS)
equal true true → true
(E-EqualTT)
equal succ(nv1) zero → false
(E-EqualSZ)
equal false true → false
(E-EqualFT)
equal succ(nv1) zero → false
(E-EqualSZ)
equal true false → false
(E-EqualTF)
equal zero zero zero → true
(E-EqualZZ)
equal false false → true
(E-EqualFF)
t1 → t'1
equal t1 t2 → equal t1' t2
(E-Equal-C1)
t2 → t'2
equal t1 t2 → equal t1 t2'
(E-Equal-C2)

Evaluation gets stuck for ill-typed terms (anti-progress?:-).

We sketch the proof by induction on the structure of a stuck term (the typing rules should be clear). We do this only for equal and plus at the toplevel, other cases being similar. If evaluation gets stuck there are always two cases to consider: either both arguments are values or at least one of them is not a value. If both are values, then a case distinction yields "ill-typedness" , because there are rules for all well-typed cases. If at least one of them is not a value, then evaluation got stuck in the argument, and we can apply the induction hypothesis.

Task 2) Termination

Here is a function "weight" that maps expressions to naturals:

    weight( t )                   = 0 for t ∈ {zero, true, false}
    weight( f(t) )                = weight(t) + 1 for f ∈ {isZero, succ, pred}
    weight( if c then t else e  ) = weight(c)+weight(t)+weight(e) + 1 
    weight( plus a b  )           = 2*weight(a)+weight(b) + 1 
  

Then we just need to observe these facts:

Proposition: If t → t', then weight(t) > weight(t')

This is proved by induction on the structure of t.

Proposition: There is no nonterminating chain of reductions. (Obviously, no expression can have a negative weight.)

Please note that "normal form" is not the same as "value": A normal form is just an expression that cannot be reduced (it might just be an expression that is stuck). Of course the safety property (progress+preservation) tells us that a well-typed term will not reduce to an ill-typed term, but this is irrelevant for the question at hand.

Task 3) Lists and lambda calculus

We use x,y,z for elements, xs, ys, zs for lists, f for functions. The example applications do not follow any evaluation strategy like call-by-name or call-by-value strictly, instead we apply beta reduction freely wherever we can, and sometimes use numbers 1,2,3 and lists [1,2,3] as abbreviations (this keeps the examples reasonably small).

a) sum: adds the elements of a list \xs. xs (\x.\y.plus x y) zero
        sum [1,2,3] = sum (\c.\n.c 1 (c 2 (c 3 n)))
        →  (\c.\n.c 1 (c 2 (c 3 n))) (\x.\y.plus x y) zero
        →* (\n.plus 1 (plus 2 (plus 3 n) zero
        →  plus 1 (plus 2 (plus 3 zero) 
        →* 6
        
b) length: determines the number of elements in a list \xs. xs (\x.\y.succ y) zero
        length [1,2,3] = length (\c.\n.c 1 (c 2 (c 3 n)))
        →  (\c.\n.c 1 (c 2 (c 3 n)))  (\x.\y.succ y) zero
        →* (\n. (\x.\y.succ y) 1 ((\x.\y.succ y) 2 ((\x.\y.succ y) 3 n) zero
        →  (\x.\y.succ y) 1 ((\x.\y.succ y) 2 ((\x.\y.succ y) 3 zero)
        →* (\y. succ y) ((\y.succ y) ((\y.succ y) zero))
        →* succ succ succ zero
        
c) append: concatenates two lists \xs. \ys. \c.\n xs c (ys c n)
        append [1] [2,3] = append (\c.\n. c 1 n) (\c.\n.c 1 (c 2 n))
        →  (\c.\n. [1] c ([2,3] c n))

        length(append [1] [2,3]) 
        →* length (\c.\n. [1] c ([2,3] c n))
        →  (\c.\n. [1] c ([2,3] c n)) (\x.\y.succ y) zero
        →  [1] (\x.\y.succ y) ([2,3] (\x.\y.succ y) zero)
        =  (\c.\n. c 1 n) (\x.\y.succ y) ([2,3] (\x.\y.succ y) zero)
        →* (\x.\y.succ y) 1 ([2,3] (\x.\y.succ y) zero)
        →* (\x.\y.succ y) 1 ((\x.\y.succ y) 2 ((\x.\y.succ y) 3 zero))
        →* succ succ succ zero
        
d) map: applies a function to every element of a list \f. \xs. \c.\n. xs (\y.\ys.c (f y) ys) n
        map (\x.(plus x 1)) [1,2] = map (\x.(plus x 1)) (\c.\n. c 1 (c 2 n))
        →  (\xs. \c \n. xs (\y.\ys. c (\x.(plus y 1)) n)) (\c.\n. c 1 (c 2 n))
        →  \c \n. (\c'.\n'. c' 1 (c' 2 n')) (\y.\ys. c (\x.(plus y 1)) n
        →  \c \n. (\n'. (\y.\ys. c (\x.(plus y 1)) 1 ((\y.\ys. c (\x.(plus y 1)) 2 n')) n
        →  \c \n. (\y.\ys. c (\x.(plus y 1)) 1 ((\y.\ys. c (\x.(plus y 1)) 2 n)
        →* \c \n. c 2 (c 3 n)
        = [2,3]
        
e) reverse: reverses a list \xs. \c.\n. (xs (\z.\zs. append zs (\c.\n. c z n)) n) c n
          [z] stands for (\c''.\n''. c'' h n''))

        reverse [1,2,3] = reverse (\c'.\n'. c' 1 (c' 2 (c' 3 n')))
        = (\xs. \c.\n. (xs (\z.\zs. append zs [z]) n) c n) [1,2,3]
        → \c.\n. ([1,2,3] (\z.\zs. append zs [z]) n) c n
        = \c.\n. (\c'.\n'. c' 1 (c' 2 (c' 3 n'))) (\z.\zs. append zs [z]) n) c n
        →  \c.\n. (\c'.\n'. c' 1 (c' 2 (c' 3 n'))) (\z.\zs. append zs [z]) c n
        →* \c.\n. ((\z.\zs. append zs [z]) 1 ((\z.\zs. append zs [z]) 2 ((\z.\zs. append zs [z]) 3 n) c n
        →* \c.\n. (append (append (append n [3]) [2]) [1]) c n
        →* \c.\n. [3,2,1] c n
        =  [3,2,1]
        

Typing Rules

Task 4) T-Eta Rules

The T-Eta rule is admissible, because every derivation that ends with T-Eta has the following structure:

                             Γ |- t: T1 → T2 
      _______________     ____________________
T-Var                                           (weakening) (x ∉ fv(t))
      Γ,  x:T1 |- x: T1    Γ, x:T1 |- t: T1 → T2 
      ________________________________________
                                                T-App 
             Γ, x:T1 |- t x: T2
         _________________________
                                    T-Abs 
          Γ |- \x:T1. t x: T1 → T2
         _________________________
                                    T-Eta (x ∉ fv(t))
              Γ |- t: T1 → T2

( The weakening rule is a rule that lets you add new assumptions to a proof, provided they don't interfere with it. For example, weakening lets you infer that if the moon is made of green cheese then 1+1=2. )

If we arrive at Γ |- t: T1 → T2 with T-Eta, we must already have had a proof of Γ |- t: T1 → T2! The smallest derivation of Γ |- t: T1 → T2 does not use T-Eta.

Propositions 9.3.1 holds, because the admissible T-Eta rule does not have an effect on the form and number of typings we can derive.

9.3.3 also holds, but the "moreover, there is just one derivation of this typing" part does obviously not hold, because there can be infinitely many derivations for a type T₁ → T₂. There is however exactly one smallest derivation in that infinite set of derivations.

Task 5) T-Eta and subtyping

Here are the rules next to each other:

    Γ |- \x:T1. t x: T1 → T2
 _________________________    
                           T-Eta (x ∉ fv(t))
       Γ |- t: T1 → T2
  T1 <: S1 S2 <: T2
 _______________________
                         S-Arrow
  S1 → S2 <: T1 → T2

We show the '⇒' direction: If Γ ⊢ t: T with T-Eta then Γ ⊢ t: T with S-Arrow

We are only interested in derivation that use T-Eta and that make use of subtyping, the other ones can be removed as seen above. A proof with T-Eta and subtyping axioms will look as follows

      _______________
T-Var
      Γ,  x:T1 |- x: T1   T1 <: S1                Γ |- t: S1 → S2 
      ______________________________          ____________________
T-Sub                                                             (weakening) (x ∉ fv(t))
      Γ,  x:T1 |- x: S1                         Γ, x:S1 |- t: S1 → S2 
      __________________________________________________________
                                                T-App 
             Γ, x:T1 |- t x: S2                                     S2 < T2
         ____________________________________________________________________
                                                                              T-Sub
             Γ, x:T1 |- t x: T2
         _________________________
                                    T-Abs 
          Γ |- \x:T1. t x: T1 → T2
         _________________________
                                    T-Eta (x ∉ fv(t))
              Γ |- t: T1 → T2

So to prove Γ |- t: T1 → T2, we needed Γ |- t: S1 → S2, T1 <: S1 and S2 < T2. But these are just what we need to apply S-Arrow. Every use of T-Eta can be replaced in this way.

Now the other direction: If Γ |- t: T with S-Arrow then Γ |- t: T with T-Eta

This is simple now, replace every occurrence of S-Arrow with the derivation tree fragment above. The resulting derivation is a well-formed derivation of Γ |- t: T that uses only T-Eta and no S-Arrow.

Task 6) Progress in FJ[optional]

Task 7) Exercise 22.3.9 (pp. 325-326 of TAPL) [optional]

These solutions will be provided later.