University of Toronto

csc324, Programming Languages, Fall 1996

Assignment 1 [10% of mark]

Out: October 8, 1996

Due: October 22, 1996, 11:59 p.m.

Objective

In this project, you will learn how to evaluate arbitrary tex2html_wrap_inline318 -expressions (both pure and applied) using S and K combinators.

In particular, we will supply you with a function compile that translates tex2html_wrap_inline318 -expressions into S K I expressions. You will write Scheme functions reduce-pure and reduce-applied to interpret S K expressions: (reduce-pure (compile E)) will be the result of evaluating E in the context of the pure tex2html_wrap_inline318 -calculus; (reduce-applied (compile E)) will be the result of evaluating E in the context of an applied tex2html_wrap_inline318 -calculus.

Background

A combinator is a tex2html_wrap_inline318 -expression without free variables. Here are three combinators:

eqnarray38

This project is based on S -combinator theory, invented as a basis for mathematical logic in the 1920's by Schöfinkel and independently in the 1930's by Curry. (Remember currying - a technique for producing functions taking just one argument from functions taking two or more arguments? That's the same guy!) The S -combinator theory defines computation over (possibly infinite) input strings using only two operators: S and K. However, for this project we will use three operators, S , K and I, and thus talk about S K I expressions.

Here's the definition of S K I expressions.

Nothing else is an S K I expression.

The last rule shows how to write function application -- it is the same as in tex2html_wrap_inline318 -calculus. As before, application associates to the left, so that tex2html_wrap_inline348 is equal to tex2html_wrap_inline350 , which is not always the same as tex2html_wrap_inline352 .

Given an S K I expression, we may rewrite its prefix (prefix of a string is an initial substring of this string) as follows:

eqnarray45

Here, E, F, G, X, and Y stand for arbitrary S K I subexpressions. [Note that tex2html_wrap_inline368 is not a subexpression of tex2html_wrap_inline370 because of left-associativity: tex2html_wrap_inline372 .]

The first rule means parentheses can be dropped when not necessary.

The second rule means that the S combinator expresses function composition (F composed with G), passing argument X to both functions (and therefore duplicating information). You can prove this rewrite rule for yourself using the definition of S .

The third rule means that operator K expresses both preservation and destruction of information -- it preserves the first argument, removes the second, and preserves all expressions thereafter. Since the application associates on the left,

eqnarray48

Finally, Iis the identity combinator. I has the same effect as S :

eqnarray50

So, I is not really necessary but is used anyway to make expressions more concise. These expressions can be used to express any computable function from strings to strings. For example, expression S makes a duplicate of its first argument:

eqnarray52

Notice that we reduced the first subexpression in parentheses, I x, just as if it were a top level expression.

In another example, the expression S (S )x reduces to three copies of x:

eqnarray54

Project Description

It is a remarkable fact that there is a function compile which takes an arbitrary (pure or applied) tex2html_wrap_inline318 -calculus expression and converts it into an equivalent S K I expression. For example,

     (compile '(\ x x))
           ->  i

     (compile '((\ x x x) 4))
           -> (s i i 4)

The syntax of lambda terms is as usual, except for the following differences.

  1. Applications at the top level must be surrounded by parentheses. For example, write EF as ( tex2html_wrap_inline344 ). But you may still write tex2html_wrap_inline348 as ( tex2html_wrap_inline348 ). Remember that application is left-associative, so that ( tex2html_wrap_inline348 ) has the same value as (( tex2html_wrap_inline344 ) tex2html_wrap_inline400 ).
  2. Use a backslash \ in place of the Greek letter tex2html_wrap_inline318 . (The backslash is supposed to look a bit like tex2html_wrap_inline318 .)
  3. Spaces must appear between the lambda and the variable being abstracted.
  4. Spaces must appear between the variable being abstracted and the body. Do not use a dot to separate them.
  5. Abstractions must be surrounded by parentheses, unless they appear as the body of another abstraction.

Here are some examples of this syntax:Write tex2html_wrap_inline406 as (\ x + x x).Write tex2html_wrap_inline408 as (\ x (\ y x)) or as (\ x \ y x)Write tex2html_wrap_inline410 as (\ x x (\ y x)).

Your goal is to write functions that apply S K I rewrite rules to reduce any S K I expression to its ``normal'' form (i.e., the expression cannot be reduced any further). When coupled with the compile function, you will have an evaluator for the (pure or applied) tex2html_wrap_inline318 -calculus.

In Scheme, we will represent top-level S K I applications with lists. For example, the application S is represented in Scheme by (s k k). Note that in the ordinary S K I rules, an application that is itself an argument in an enclosing application must always be surrounded by parentheses in order to override left-associativity.

Stage 1

Implement the rewrite rules. We have four rewrite rules, and thus there will be four functions.
  1. Function reduce-paren removes unnecessary parentheses around the prefix of its argument. If its argument is an S K I expression that is not an application, i.e. its argument is a list of one element, then it removes those parentheses:
     
        (reduce-paren '((X ...) E ...))
              -> (X ... E ...)
        (reduce-paren '(x))
              -> x
    It will only be called when its argument actually has such unnecessary parentheses. Example:
     
        (reduce-paren '((a b c d) a b))
              -> (a b c d a b)
        (reduce-paren '(42))
              -> 42
  2. Function reduce-i will always be given a list of at least two elements, the first of which is the name i. It returns the result of applying the I rewrite rule:
        (reduce-i '(i x ...))
              -> (x ...)
    Example:
        (reduce-i '(i x k s y))
             -> (x k s y)
  3. Function reduce-k will always be given a list of at least three elements, the first of which is the name k. It returns the result of applying the K rewrite rule:
        (reduce-k '(k x y ...))
            -> (x ...)
    Example:
        (reduce-k '(k (x 2) q z f))
            -> ((x 2) z f)
  4. Function reduce-s will always be given a list of at least four elements, the first of which is the name s. It returns the result of applying the S rewrite rule:
        (reduce-s '(s f g x ...)
           -> (f x (g x) ...)
    Example:
        (reduce-s '(s s i x i x))
           -> (s x (i x) i x)

Stage 2

Write function reduce-pure which reduces an arbitrary S K I to its normal form in the context of the pure tex2html_wrap_inline318 -calculus. These are some of the auxiliary functions for reduce-pure:
  1. Function reduce-pure-outer is given an S K I expression as its one argument. If none of the rewrite rules apply to its argument at the top level, then it returns its argument unchanged. Otherwise, it returns the result of applying the appropriate rewrite rule (i.e. one of reduce-paren, reduce-i, reduce-k, or reduce-s). For example, if its argument is a list of at least two elements, the first of which is the symbol i, then it returns the result of passing its argument to the reduce-i function. Examples:
       (reduce-pure-outer '(k (i y) x z (i 4)))
             -> ((i y) z (i 4))
       (reduce-pure-outer '((x y)))
             -> (x y)
       (reduce-pure-outer '(s x))
             -> (s x)
    In the last example, the S rule could not be applied because there weren't enough arguments to the S function.
  2. Function reduce-pure-whnf calls reduce-pure-outer until no more rules can be applied. The expression is now in what is called ``Weak Head Normal Form''.
    Hint: No more reductions are possible if result of reduce-pure-outer for some expression E equals E. Use operation equal? to test for equality. So, you need to stop when
        (equal? (reduce-pure-outer E) E)
    Example:
        (reduce-pure-whnf '(k i (x y) z (i 42)))
             -> (z (i 42))
  3. Finally, function reduce-pure applies reduce-pure-whnf to its argument. If the result is a list, then it applies itself to all the elements of that list. If the result was not a list, then that is returned. The resulting value is in ``Normal Form''. Example:
       (reduce-pure '(s (s i i) i x))
            -> (x x x)

As described earlier, (reduce-pure (compile E)) for any lambda expression E will be the normal form of E if one exists. (However, if the normal form of E still contains tex2html_wrap_inline318 abstractions, then they will be expressed in S K I form.)

Stage 3

We will now extend our tex2html_wrap_inline318 -calculus evaluator to an applied tex2html_wrap_inline318 -calculus by adding rewrite rules for some constants. The list of constants is: if, iszero, pred, succ, fix, and plus. We also have constants true, and false, although they have no rewrite rules associated with them. (Note that these are the same constants as described in Section 14.1 of Sethi's book, except that we've added plus as a primitive operation for the sake of efficiency.) The extensions will build a function reduce-applied which evaluates an applied S K I expression in the context of this applied tex2html_wrap_inline318 -calculus.

First, you will write functions that implement reductions for these constants.

Second, you will write functions reduce-applied-outer, reduce-applied-whnf, and reduce-applied which are modifications of reduce-pure-outer, reduce-pure-sequence, and reduce-pure, respectively.

Submission (electronic)

Submit a tar file with
  1. Well-documented source code. All the code for the pure reducer should be in a file called pure.s. The extra code needed for the applied reducer should be in a file called pure.s. (For example, the definition of reduce-s should appear in pure.s but not in applied.s.)
  2. Test program test.s. This will load compile.s, pure.s and and applied.s and then run and display test cases. We will supply you with the source file compile.s that contains the compile function. Include enough test cases to test your functions. Don't forget border cases.
  3. Output showing the operation of your program.
  4. (Optional) README file with instructions on how to run your program.
Note that we will rerun your program with, so please do not change the output of your program!!!!!

Grading

The marking scheme will be as follows:
 
		 Testing 		 10 		 
(Has the program been tested accordingly?)

Style 25 (The program should be written using functional programming style.)

Documentation 10 (Explanation for each module and the entire program.)

Correctness 55

David Neto will grade this assignment. He will have office hours on Friday October 11, 1996, from 4-5pm in SF3207, and on Monday October 21, 1996, from 3-4pm in SF3207.

Notes

Acknowledgment

This project was suggested by David Neto. Implementation of function compile is also due to him.



Marsha Chechik
Thu Oct 10 13:34:43 EDT 1996