Exercise 2 Untyped Lambda-Calculus |
|||||
English only |
|||||
This page has been updated with sections Tips and Partial Solution. Food for thought has been moved to the main course page. The parial implementation had a bug in EvaluatorPhase::isNumericVal (the solution fixed it). Sorry. This page is best viewed with Mozilla Firefox or any other browser that displays Unicode math symbols correctly. The symbol ⊢ should look roughly like |-. Administrative Issue: Please register in groups of two during this session.Emacs is installed now! set the environment variable HOME to your home directory, and create a _emacs file there with these lines (setq load-path (cons (expand-file-name "C:/Program Files/Scala/support/emacs") load-path) ) (require 'scala-mode) (require 'scala-mode-auto) (global-font-lock-mode 1) ;; syntax highlighting (transient-mark-mode t) ;; highlight the active (selected) region Exercise 2 (untyped) Lambda CalculusThis exercise aims to test and deepen your understanding of the lambda
calculus. For this, the lambda calculus is extended with
arithmetic expressions that we have seen last week.
The terms
Renaming can be avoided using a nameless representation for terms. The idea is to replaces name references by "structural references" (a number that indicates how much lambdas we have to go up). Substitution then means replacing a number If E contains abstractions, the numbers that point to outer abstractions need to be shifted in order to preserve the meaning. But references that point to
abstractions inside
Task 2.1 (from TAPL page 67)Write down the nameless representations for these terms (you can keep the names in the abstractions). \s.\z.z \s.\z.s (s z) \m.\n.\s.\z.m s (n s) \f.\x.f (\y. x x y) (\y. x x y) (\x.(\x.x)) (\x.x) Task 2.2 From named terms to de Bruijn terms...
Write a program that does this mechanical translation. Download and
unpack the partial implementation and
complete
Use the class
In You can compile with scalac -d classes src\lambda\*.scalaYou can test with scala lambda.Main -deBruijn <sourcefile1> <sourcefile2> ...Some test files with the extension ".lam" can be found in the directory test .
Task 2.3 ...and backWith the help of the debugging information (the names in the abstractions),
we can get back to terms with names.
Implement method scala lambda.Main -deBruijn -print <sourcefile1> <sourcefile2> ... Task 2.4 Call-By-Value EvaluatorComplete all missing methods in scala lambda.Main <sourcefile1> <sourcefile2> ... Run some tests. If you are convinced that it works, try to evaluate Task 2.5 Call-By-Name EvaluatorYou have seen the call-by-name evaluation strategy. Here are the rules: we reduce an application of a lambda abstraction even though the argument is not necessarily value. The congruence rule needs to be adapted in order to keep the strategy deterministic.
Which line do you have to change in your implementation to get
call-by-name evalution? What behaviour can be observed when running
call-by-name on the file
TipsThe class >val x = new Context(); // x is an empty map >val y = x.update("A", NameBind); // y is a map { A -> NameBind } >y("A") NameBind >x("A"); // x is not modified error: key not foundApart from applying a context ctx, one can also make a get: >def f(y:Context) = { // y is a context >y.get("B").match { case Some(z) => ...//y contains "B" case None => ...//y does NOT contain "B" } For error reporting, you can use the method case RawVar(inf, x) => ...Main.reportError(inf, "undefined variable:"+x);
Partial SolutionHere are solutions to Expr.scala and DeBruijnPhase.scala
The only interesting cases in the match of de Bruijn translation
Here is the solution for the terms from above: removeNames(\s.\z.z) = \s.\z.0 removeNames(\s.\z.s (s z)) = \s.\z.1 (1 0) removeNames(\m.\n.\s.\z.m s (n s)) = \m.\n.\s.\z.3 1 (2 1) removeNames(\f.\x.f (\y. x x y) (\y. x x y)) = \f.\x.f (\y. 1 1 0) (\y.1 1 0) removeNames((\x.(\x.x)) (\x.x)) = (\x.(\x.0)) (\x.0) You have some more time to complete |
|