
        A Language with Nested, First Class, Anonymous Functions


An expression in this language is defined by the following grammar.

       Prog ::= Exp
              | '(' 'prog' Exp* Exp ')'

        Exp ::= Lambda
              | Fun
              | Apply
              | If
              | While
              | Begin
              | Var
              | Set
              | Print
              | BExp
              | AExp
              | INTEGER
              | BOOLEAN
              | VARIABLE

     Lambda ::= '(' 'lambda' VARIABLE* Exp ')'  // formal parameters followed by function body

        Fun ::= '(' 'fun' VARIABLE Lambda ')'   // a function declaration

      Apply ::= '(' 'apply' Exp Exp* ')'        // function value followed by actual parameters

         If ::= '(' 'if' Exp Exp Exp ')'

      While ::= '(' 'while' Exp Exp ')'

      Begin ::= '(' 'begin' Exp+ ')'

        Var ::= '(' 'var' VARIABLE Exp ')'

        Set ::= '(' 'set' VARIABLE Exp ')'

      Print ::= '(' 'print' Exp ')'

       BExp ::= '(' '||'  Exp Exp+ ')'
              | '(' '&&'  Exp Exp+ ')'
              | '(' '!'   Exp ')'
              | '('  EqOp Exp Exp ')'
              | '(' RelOp Exp Exp ')'

       EqOp ::= '==' | '!='
      RelOp ::= '<' | '>' | '<=' | '>='

       AExp ::= '(' '+' Exp Exp* ')'
              | '(' '-' Exp Exp? ')'
              | '(' '*' Exp Exp+ ')'
              | '(' '/' Exp Exp  ')'
              | '(' '%' Exp Exp  ')'
              | '(' '^' Exp Exp  ')'

    INTEGER ::= [-|+][0-9]+
    BOOLEAN ::= 'true' | 'false'
   VARIABLE ::= [a-zA-Z][a-zA-Z0-9]*


If you look at the syntax for Language_7, you will notice Lambda is not an expression. In this language, the only change we make is to add Lambda to the list of expressions. This gives the language a new, and elegant, expressiveness.

Consider this example from Language_7.

   (fun f1 (lambda x (+ x 1))
   (fun f2 (lambda x (+ x 2))
   (fun g  (lambda n (if (== 0 (% n 2)) f2 f1))) // return f1 or f2

Unless we have a specific need for the names f1 and f2, it would be better to get rid of those two global names and "hide" those two functions (and their names) as nested functions inside of g. In Language_8 we can write the following.

   (var g (lambda n
            (begin
              (var f1 (lambda x (+ x 1))   // the names f1 and f2 are local to g
              (var f2 (lambda x (+ x 2))
              (if (== 0 (% n 2)) f2 f1)))) // return f1 or f2

But in Language_8, we can use the fact that lambda is a first class expression to write g in an even more compact form, without any need for the temporary names f1 and f2.

   (var g (lambda n (if (== 0 (% n 2))
                        (lambda x (+ x 1)
                        (lambda x (+ x 2))))

So g returns either the (anonymous) lambda-expression (lambda x (+ x 1) or the (anonymous) lambda-expression (lambda x (+ x 2).


In this language, the Fun expression is redundant with the Var expression (they both can assign a "function value" to an identifier, but Var can also assign integer or boolean values to an identifier). We could eliminate the Fun expression, but we shall keep it. Some languages like to make the definition of function identifiers look syntactically different from the definition of "regular" identifiers. But a "function value" (or "lambda value", or "closure") is not really any different than an "integer value" or a "boolean value". They are all "first class values". So we could use Var expressions for all of our variable declarations. (Notice that the ast2infix() method prints functions defined using Fun in a different format from functions defined using Var.)


There is another way to think about the difference between Langauge_7 and Language_9. When we write
   (var x 7)
or
   (var x true)
we are setting the value of an identifier by using a "literal value", the number 7 in the first case and the boolean value true in the second case. That is in contrast to expressions like
   (var x y)
   (var x (+ 3 4))
   (var x (apply f 3))
where we are setting the value of an identifier using the value of some other expression.

When we write
   (var f (lambda x (* x x)))
we can think of this as setting the value of the identifier f to be the "literal function" (lambda x (* x x)).

When we write
   (+ 3 4)
we are telling the '+' operator to add the literal values 3 and 4.

When we write
   (apply (lambda x (* x x)) 7)
we are telling 'apply' to call the "literal function" (lambda x (* x x)).

So we can think of the anonymous lambda expressions in Language_8 as a form of "literal function values". In Language_7, every function value has to be first assigned to an identifier (using 'fun') before the function value can be used in any way. Imagine a programming language where you had to use a special syntax to give a number (like 7) a name before you could use it in any expression. That would be a very awkward language to use. But Language_7 (and C, C++, Java) feel that awkward, when it comes to function values, when compared to Language_8 (or Scheme, ML, Haskell). Most modern programming languages now provide "function literals", which are usually called "lambda expressions".


To implement Language_8 we need to define a new method, evaluateLambda(). But all of the code needed for this method can be moved from the evaluateFun() method in Language_7.
