Lecture #7, Tuesday, January 31st
=================================
 Functions & Function Values
 Implementing First Class Functions
 Sidenote: how important is it to have *anonymous* functions?
 The FLANG Language

# Functions & Function Values
> [PLAI §4]
Now that we have a form for local bindings, which forced us to deal with
proper substitutions and everything that is related, we can get to
functions. The concept of a function is itself very close to
substitution, and to our `with` form. For example, when we write:
{with {x 5}
{* x x}}
then the `{* x x}` body is itself parametrized over some value for `x`.
If we take this expression and take out the `5`, we're left with
something that has all of the necessary ingredients of a function  a
bunch of code that is parameterized over some input identifier:
{with {x}
{* x x}}
We only need to replace `with` and use a proper name that indicates that
it's a function:
{fun {x}
{* x x}}
Now we have a new form in our language, one that should have a function
as its meaning. As we have seen in the case of `with` expressions, we
also need a new form to *use* these functions. We will use `call` for
this, so that
{call {fun {x} {* x x}}
5}
will be the same as the original `with` expression that we started with
 the `fun` expression is like the `with` expression with no value,
and applying it on `5` is providing that value back:
{with {x 5}
{* x x}}
Of course, this does not help much  all we get is a way to use local
bindings that is more verbose from what we started with. What we're
really missing is a way to *name* these functions. If we get the right
evaluation rules, we can evaluate a `fun` expression to some value 
which will allow us to bind it to a variable using `with`. Something
like this:
{with {sqr {fun {x} {* x x}}}
{+ {call sqr 5}
{call sqr 6}}}
In this expression, we say that `x` is the formal parameter (or
argument), and the `5` and `6` are actual parameters (sometimes
abbreviated as formals and actuals). Note that naming functions often
helps, but many times there are small functions that are fine to specify
without a name  for example, consider a twostage addition function,
where there is no apparent good name for the returned function:
{with {add {fun {x}
{fun {y}
{+ x y}}}}
{call {call add 8} 9}}

# Implementing First Class Functions
> [PLAI §6] (uses some stuff from [PLAI §5], which we do later)
This is a simple plan, but it is directly related to how functions are
going to be used in our language. We know that `{call {fun {x} E1} E2}`
is equivalent to a `with` expression, but the new thing here is that we
do allow writing just the `{fun ...}` expression by itself, and
therefore we need to have some meaning for it. The meaning, or the value
of this expression, should roughly be "an expression that needs a value
to be plugged in for `x`". In other words, our language will have these
new kinds of values that contain an expression to be evaluated later on.
There are three basic approaches that classify programming languages in
relation to how the deal with functions:
1. First order: functions are not real values. They cannot be used or
returned as values by other functions. This means that they cannot be
stored in data structures. This is what most "conventional" languages
used to have in the past. (You will be implementing such a language
in homework 4.)
An example of such a language is the Beginner Student language that
is used in HtDP, where the language is intentionally firstorder to
help students write correct code (at the early stages where using a
function as a value is usually an error). It's hard to find practical
modern languages that fall in this category.
2. Higher order: functions can receive and return other functions as
values. This is what you get with C and modern Fortran.
3. First class: functions are values with all the rights of other
values. In particular, they can be supplied to other functions,
returned from functions, stored in data structures, and new functions
can be created at runtime. (And most modern languages have first
class functions.)
The last category is the most interesting one. Back in the old days,
complex expressions were not firstclass in that they could not be
freely composed. This is still the case in machinecode: as we've seen
earlier, to compute an expression such as
(b + sqrt(b^2  4*a*c)) / 2a
you have to do something like this:
x = b * b
y = 4 * a
y = y * c
x = x  y
x = sqrt(x)
y = b
x = y + x
y = 2 * a
s = x / y
In other words, every intermediate value needs to have its own name. But
with proper ("highlevel") programming languages (at least most of
them...) you can just write the original expression, with no names for
these values.
With firstclass functions something similar happens  it is possible
to have complex expressions that consume and return functions, and they
do not need to be named.
What we get with our `fun` expression (if we can make it work) is
exactly this: it generates a function, and you can choose to either bind
it to a name, or not. The important thing is that the value exists
independently of a name.
This has a major effect on the "personality" of a programming language
as we will see. In fact, just adding this feature will make our language
much more advanced than languages with just higherorder or firstorder
functions.

Quick Example: the following is working JavaScript code, that uses first
class functions.
function foo(x) {
function bar(y) { return x + y; }
return bar;
}
function main() {
var f = foo(1);
var g = foo(10);
return [f(2), g(2)];
}
Note that the above definition of `foo` does *not* use an anonymous
"lambda expression"  in Racket terms, it's translated to
(define (foo x)
(define (bar y) (+ x y))
bar)
The returned function is not anonymous, but it's not really named
either: the `bar` name is bound only inside the body of `foo`, and
outside of it that name no longer exists since it's not its scope. It
gets used in the printed form if the function value is displayed, but
this is merely a debugging aid. The anonymous `lambda` version that is
common in Racket can be used in JavaScript too:
function foo(x) {
return function(y) { return x + y; }
}
> Sidenote: GCC includes extensions that allow internal function
> definitions, but it still does not have first class functions 
> trying to do the above is broken:
>
> #include
> typedef int(*int2int)(int);
> int2int foo(int x) {
> int bar(int y) { return x + y; }
> return bar;
> }
> int main() {
> int2int f = foo(1);
> int2int g = foo(10);
> printf(">> %d, %d\n", f(2), g(2));
> }

## Sidenote: how important is it to have *anonymous* functions?
You'll see many places where people refer to the feature of firstclass
functions as the ability to create *anonymous* functions, but this is a
confusion and it's not accurate. Whether a function has a name or not is
not the important question  instead, the important question is
whether functions can exist with no *bindings* that refers to them.
As a quick example in Racket:
(define (foo x)
(define (bar y) (+ x y))
bar)
in Javascript:
function foo(x) {
function bar(y) {
return x + y;
}
return bar;
}
and in Python:
def foo(x):
def bar(y):
return x + y
return bar
In all three of these, we have a `foo` function that returns a function
*named* `bar`  but the `bar` name, is only available in the scope of
`foo`. The fact that the name is displayed as part of the textual
rendering of the function value is merely a debugging feature.

# The FLANG Language
Now for the implementation  we call this new language FLANG.
First, the BNF:
::=
 { + }
 {  }
 { * }
 { / }
 { with { } }

 { fun { } }
 { call }
And the matching type definition:
(definetype FLANG
[Num Number]
[Add FLANG FLANG]
[Sub FLANG FLANG]
[Mul FLANG FLANG]
[Div FLANG FLANG]
[Id Symbol]
[With Symbol FLANG FLANG]
[Fun Symbol FLANG] ; No namedexpression
[Call FLANG FLANG])
The parser for this grammar is, as usual, straightforward:
(: parsesexpr : Sexpr > FLANG)
;; parses sexpressions into FLANGs
(define (parsesexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(symbol: name) (Id name)]
[(cons 'with more)
(match sexpr
[(list 'with (list (symbol: name) named) body)
(With name (parsesexpr named) (parsesexpr body))]
[else (error 'parsesexpr "bad `with' syntax in ~s" sexpr)])]
[(cons 'fun more)
(match sexpr
[(list 'fun (list (symbol: name)) body)
(Fun name (parsesexpr body))]
[else (error 'parsesexpr "bad `fun' syntax in ~s" sexpr)])]
[(list '+ lhs rhs) (Add (parsesexpr lhs) (parsesexpr rhs))]
[(list ' lhs rhs) (Sub (parsesexpr lhs) (parsesexpr rhs))]
[(list '* lhs rhs) (Mul (parsesexpr lhs) (parsesexpr rhs))]
[(list '/ lhs rhs) (Div (parsesexpr lhs) (parsesexpr rhs))]
[(list 'call fun arg)
(Call (parsesexpr fun) (parsesexpr arg))]
[else (error 'parsesexpr "bad syntax in ~s" sexpr)]))
We also need to patch up the substitution function to deal with these
things. The scoping rule for the new function form is, unsurprisingly,
similar to the rule of `with`, except that there is no extra expression
now, and the scoping rule for `call` is the same as for the arithmetic
operators:
N[v/x] = N
{+ E1 E2}[v/x] = {+ E1[v/x] E2[v/x]}
{ E1 E2}[v/x] = { E1[v/x] E2[v/x]}
{* E1 E2}[v/x] = {* E1[v/x] E2[v/x]}
{/ E1 E2}[v/x] = {/ E1[v/x] E2[v/x]}
y[v/x] = y
x[v/x] = v
{with {y E1} E2}[v/x] = {with {y E1[v/x]} E2[v/x]}
{with {x E1} E2}[v/x] = {with {x E1[v/x]} E2}
{call E1 E2}[v/x] = {call E1[v/x] E2[v/x]}
{fun {y} E}[v/x] = {fun {y} E[v/x]}
{fun {x} E}[v/x] = {fun {x} E}
And the matching code:
(: subst : FLANG Symbol FLANG > FLANG)
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define (subst expr from to)
(cases expr
[(Num n) expr]
[(Add l r) (Add (subst l from to) (subst r from to))]
[(Sub l r) (Sub (subst l from to) (subst r from to))]
[(Mul l r) (Mul (subst l from to) (subst r from to))]
[(Div l r) (Div (subst l from to) (subst r from to))]
[(Id name) (if (eq? name from) to expr)]
[(With boundid namedexpr boundbody)
(With boundid
(subst namedexpr from to)
(if (eq? boundid from)
boundbody
(subst boundbody from to)))]
[(Call l r) (Call (subst l from to) (subst r from to))]
[(Fun boundid boundbody)
(if (eq? boundid from)
expr
(Fun boundid (subst boundbody from to)))]))

Now, before we start working on an evaluator, we need to decide on what
exactly do we use to represent values of this language. Before we had
functions, we had only number values and we used Racket numbers to
represent them. Now we have two kinds of values  numbers and
functions. It seems easy enough to continue using Racket numbers to
represent numbers, but what about functions? What should be the result
of evaluating
{fun {x} {+ x 1}}
? Well, this is the new toy we have: it should be a function value,
which is something that can be used just like numbers, but instead of
arithmetic operations, we can `call` these things. What we need is a way
to avoid evaluating the body expression of the function  *delay* it
 and instead use some value that will contain this delayed expression
in a way that can be used later.
To accommodate this, we will change our implementation strategy a
little: we will use our syntax objects for numbers (`(Num n)` instead of
just `n`), which will be a little inconvenient when we do the arithmetic
operations, but it will simplify life by making it possible to evaluate
functions in a similar way: simply return their own syntax object as
their values. The syntax object has what we need: the body expression
that needs to be evaluated later when the function is called, and it
also has the identifier name that should be replaced with the actual
input to the function call. This means that evaluating:
(Add (Num 1) (Num 2))
now yields
(Num 3)
and a number `(Num 5)` evaluates to `(Num 5)`.
In a similar way, `(Fun 'x (Num 2))` evaluates to `(Fun 'x (Num 2))`.
Why would this work? Well, because `call` will be very similar to `with`
 the only difference is that its arguments are ordered a little
differently, being retrieved from the function that is applied and the
argument.
The formal evaluation rules are therefore treating functions like
numbers, and use the syntax object to represent both values:
eval(N) = N
eval({+ E1 E2}) = eval(E1) + eval(E2)
eval({ E1 E2}) = eval(E1)  eval(E2)
eval({* E1 E2}) = eval(E1) * eval(E2)
eval({/ E1 E2}) = eval(E1) / eval(E2)
eval(id) = error!
eval({with {x E1} E2}) = eval(E2[eval(E1)/x])
eval(FUN) = FUN ; assuming FUN is a function expression
eval({call E1 E2})
= eval(Ef[eval(E2)/x]) if eval(E1) = {fun {x} Ef}
= error! otherwise
Note that the last rule could be written using a translation to a `with`
expression:
eval({call E1 E2})
= eval({with {x E2} Ef}) if eval(E1) = {fun {x} Ef}
= error! otherwise
And alternatively, we could specify `with` using `call` and `fun`:
eval({with {x E1} E2}) = eval({call {fun {x} E2} E1})
There is a small problem in these rules which is intuitively seen by the
fact that the evaluation rule for a `call` is expected to be very
similar to the one for arithmetic operations. We now have two kinds of
values, so we need to check the arithmetic operation's arguments too:
eval({+ E1 E2}) = N1 + N2
if eval(E1), eval(E2) evaluate to numbers N1, N2
otherwise error!
...
The corresponding code is:
(: eval : FLANG > FLANG) ;*** note return type
;; evaluates FLANG expressions by reducing them to *expressions* but
;; only expressions that stand for values: only `Fun`s and `Num`s
(define (eval expr)
(cases expr
[(Num n) expr] ;*** change here
[(Add l r) (arithop + (eval l) (eval r))]
[(Sub l r) (arithop  (eval l) (eval r))]
[(Mul l r) (arithop * (eval l) (eval r))]
[(Div l r) (arithop / (eval l) (eval r))]
[(With boundid namedexpr boundbody)
(eval (subst boundbody
boundid
(eval namedexpr)))] ;*** no `(Num ...)'
[(Id name) (error 'eval "free identifier: ~s" name)]
[(Fun boundid boundbody) expr] ;*** similar to `Num'
[(Call (Fun boundid boundbody) argexpr) ;*** nested pattern
(eval (subst boundbody ;*** just like `with'
boundid
(eval argexpr)))]
[(Call something argexpr)
(error 'eval "`call' expects a function, got: ~s" something)]))
Note that the `Call` case is doing the same thing we do in the `With`
case. In fact, we could have just *generated* a `With` expression and
evaluate that instead:
...
[(Call (Fun boundid boundbody) argexpr)
(eval (With boundid argexpr boundbody))]
...
The `arithop` function is in charge of checking that the input values
are numbers (represented as FLANG numbers), translating them to plain
numbers, performing the Racket operation, then rewrapping the result in
a `Num`. Note how its type indicates that it is a higherorder function.
(: arithop : (Number Number > Number) FLANG FLANG > FLANG)
;; gets a Racket numeric binary operator, and uses it within a FLANG
;; `Num' wrapper (note the H.O. type, and note the hack of the `val`
;; name which is actually an AST that represents a runtime value)
(define (arithop op val1 val2)
(Num (op (Num>number val1) (Num>number val2))))
It uses the following function to convert FLANG numbers to Racket
numbers. (Note that `else` is almost always a bad idea since it can
prevent the compiler from showing you places to edit code  but this
case is an exception since we never want to deal with anything other
than `Num`s.) The reason that this function is relatively trivial is
that we chose the easy way and represented numbers using Racket numbers,
but we could have used strings or anything else.
(: Num>number : FLANG > Number)
;; convert a FLANG number to a Racket one
(define (Num>number e)
(cases e
[(Num n) n]
[else (error 'arithop "expected a number, got: ~s" e)]))
We can also make things a little easier to use if we make `run` convert
the result to a number:
(: run : String > Number)
;; evaluate a FLANG program contained in a string
(define (run str)
(let ([result (eval (parse str))])
(cases result
[(Num n) n]
[else (error 'run "evaluation returned a nonnumber: ~s"
result)])))
Adding few simple tests we get:
;; The Flang interpreter
#lang pl
#
The grammar:
::=
 { + }
 {  }
 { * }
 { / }
 { with { } }

 { fun { } }
 { call }
Evaluation rules:
subst:
N[v/x] = N
{+ E1 E2}[v/x] = {+ E1[v/x] E2[v/x]}
{ E1 E2}[v/x] = { E1[v/x] E2[v/x]}
{* E1 E2}[v/x] = {* E1[v/x] E2[v/x]}
{/ E1 E2}[v/x] = {/ E1[v/x] E2[v/x]}
y[v/x] = y
x[v/x] = v
{with {y E1} E2}[v/x] = {with {y E1[v/x]} E2[v/x]} ; if y =/= x
{with {x E1} E2}[v/x] = {with {x E1[v/x]} E2}
{call E1 E2}[v/x] = {call E1[v/x] E2[v/x]}
{fun {y} E}[v/x] = {fun {y} E[v/x]} ; if y =/= x
{fun {x} E}[v/x] = {fun {x} E}
eval:
eval(N) = N
eval({+ E1 E2}) = eval(E1) + eval(E2) \ if both E1 and E2
eval({ E1 E2}) = eval(E1)  eval(E2) \ evaluate to numbers
eval({* E1 E2}) = eval(E1) * eval(E2) / otherwise error!
eval({/ E1 E2}) = eval(E1) / eval(E2) /
eval(id) = error!
eval({with {x E1} E2}) = eval(E2[eval(E1)/x])
eval(FUN) = FUN ; assuming FUN is a function expression
eval({call E1 E2}) = eval(Ef[eval(E2)/x])
if eval(E1)={fun {x} Ef}, otherwise error!
#
(definetype FLANG
[Num Number]
[Add FLANG FLANG]
[Sub FLANG FLANG]
[Mul FLANG FLANG]
[Div FLANG FLANG]
[Id Symbol]
[With Symbol FLANG FLANG]
[Fun Symbol FLANG]
[Call FLANG FLANG])
(: parsesexpr : Sexpr > FLANG)
;; parses sexpressions into FLANGs
(define (parsesexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(symbol: name) (Id name)]
[(cons 'with more)
(match sexpr
[(list 'with (list (symbol: name) named) body)
(With name (parsesexpr named) (parsesexpr body))]
[else (error 'parsesexpr "bad `with' syntax in ~s" sexpr)])]
[(cons 'fun more)
(match sexpr
[(list 'fun (list (symbol: name)) body)
(Fun name (parsesexpr body))]
[else (error 'parsesexpr "bad `fun' syntax in ~s" sexpr)])]
[(list '+ lhs rhs) (Add (parsesexpr lhs) (parsesexpr rhs))]
[(list ' lhs rhs) (Sub (parsesexpr lhs) (parsesexpr rhs))]
[(list '* lhs rhs) (Mul (parsesexpr lhs) (parsesexpr rhs))]
[(list '/ lhs rhs) (Div (parsesexpr lhs) (parsesexpr rhs))]
[(list 'call fun arg)
(Call (parsesexpr fun) (parsesexpr arg))]
[else (error 'parsesexpr "bad syntax in ~s" sexpr)]))
(: parse : String > FLANG)
;; parses a string containing a FLANG expression to a FLANG AST
(define (parse str)
(parsesexpr (string>sexpr str)))
(: subst : FLANG Symbol FLANG > FLANG)
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define (subst expr from to)
(cases expr
[(Num n) expr]
[(Add l r) (Add (subst l from to) (subst r from to))]
[(Sub l r) (Sub (subst l from to) (subst r from to))]
[(Mul l r) (Mul (subst l from to) (subst r from to))]
[(Div l r) (Div (subst l from to) (subst r from to))]
[(Id name) (if (eq? name from) to expr)]
[(With boundid namedexpr boundbody)
(With boundid
(subst namedexpr from to)
(if (eq? boundid from)
boundbody
(subst boundbody from to)))]
[(Call l r) (Call (subst l from to) (subst r from to))]
[(Fun boundid boundbody)
(if (eq? boundid from)
expr
(Fun boundid (subst boundbody from to)))]))
(: Num>number : FLANG > Number)
;; convert a FLANG number to a Racket one
(define (Num>number e)
(cases e
[(Num n) n]
[else (error 'arithop "expected a number, got: ~s" e)]))
(: arithop : (Number Number > Number) FLANG FLANG > FLANG)
;; gets a Racket numeric binary operator, and uses it within a FLANG
;; `Num' wrapper
(define (arithop op val1 val2)
(Num (op (Num>number val1) (Num>number val2))))
(: eval : FLANG > FLANG)
;; evaluates FLANG expressions by reducing them to *expressions* but
;; only expressions that stand for values: only `Fun`s and `Num`s
(define (eval expr)
(cases expr
[(Num n) expr]
[(Add l r) (arithop + (eval l) (eval r))]
[(Sub l r) (arithop  (eval l) (eval r))]
[(Mul l r) (arithop * (eval l) (eval r))]
[(Div l r) (arithop / (eval l) (eval r))]
[(With boundid namedexpr boundbody)
(eval (subst boundbody
boundid
(eval namedexpr)))]
[(Id name) (error 'eval "free identifier: ~s" name)]
[(Fun boundid boundbody) expr]
[(Call (Fun boundid boundbody) argexpr)
(eval (subst boundbody
boundid
(eval argexpr)))]
[(Call something argexpr)
(error 'eval "`call' expects a function, got: ~s" something)]))
(: run : String > Number)
;; evaluate a FLANG program contained in a string
(define (run str)
(let ([result (eval (parse str))])
(cases result
[(Num n) n]
[else (error 'run "evaluation returned a nonnumber: ~s"
result)])))
;; tests
(test (run "{call {fun {x} {+ x 1}} 4}")
=> 5)
(test (run "{with {add3 {fun {x} {+ x 3}}}
{call add3 1}}")
=> 4)
(test (run "{with {add3 {fun {x} {+ x 3}}}
{with {add1 {fun {x} {+ x 1}}}
{with {x 3}
{call add1 {call add3 x}}}}}")
=> 7)

There is still a problem with this version. First a question  if
`call` is similar to arithmetic operations (and to `with` in what it
actually does), then how come the code is different enough that it
doesn't even need an auxiliary function?
Second question: what *should* happen if we evaluate these code
snippets:
(run "{with {add {fun {x}
{fun {y}
{+ x y}}}}
{call {call add 8} 9}}")
(run "{with {identity {fun {x} x}}
{with {foo {fun {x} {+ x 1}}}
{call {call identity foo} 123}}}")
(run "{call {call {fun {x} {call x 1}}
{fun {x} {fun {y} {+ x y}}}}
123}")
Third question, what *will* happen if we do the above?
What we're missing is an evaluation of the function expression, in case
it's not a literal `fun` form. The following fixes this:
(: eval : FLANG > FLANG)
;; evaluates FLANG expressions by reducing them to *expressions* but
;; only expressions that stand for values: only `Fun`s and `Num`s
(define (eval expr)
(cases expr
[(Num n) expr]
[(Add l r) (arithop + (eval l) (eval r))]
[(Sub l r) (arithop  (eval l) (eval r))]
[(Mul l r) (arithop * (eval l) (eval r))]
[(Div l r) (arithop / (eval l) (eval r))]
[(With boundid namedexpr boundbody)
(eval (subst boundbody
boundid
(eval namedexpr)))]
[(Id name) (error 'eval "free identifier: ~s" name)]
[(Fun boundid boundbody) expr]
[(Call funexpr argexpr)
(let ([fval (eval funexpr)]) ;*** need to evaluate this!
(cases fval
[(Fun boundid boundbody)
(eval (subst boundbody
boundid
(eval argexpr)))]
[else (error 'eval "`call' expects a function, got: ~s"
fval)]))]))
The complete code is:
;;; <<>>
;; The Flang interpreter
#lang pl
#
The grammar:
::=
 { + }
 {  }
 { * }
 { / }
 { with { } }

 { fun { } }
 { call }
Evaluation rules:
subst:
N[v/x] = N
{+ E1 E2}[v/x] = {+ E1[v/x] E2[v/x]}
{ E1 E2}[v/x] = { E1[v/x] E2[v/x]}
{* E1 E2}[v/x] = {* E1[v/x] E2[v/x]}
{/ E1 E2}[v/x] = {/ E1[v/x] E2[v/x]}
y[v/x] = y
x[v/x] = v
{with {y E1} E2}[v/x] = {with {y E1[v/x]} E2[v/x]} ; if y =/= x
{with {x E1} E2}[v/x] = {with {x E1[v/x]} E2}
{call E1 E2}[v/x] = {call E1[v/x] E2[v/x]}
{fun {y} E}[v/x] = {fun {y} E[v/x]} ; if y =/= x
{fun {x} E}[v/x] = {fun {x} E}
eval:
eval(N) = N
eval({+ E1 E2}) = eval(E1) + eval(E2) \ if both E1 and E2
eval({ E1 E2}) = eval(E1)  eval(E2) \ evaluate to numbers
eval({* E1 E2}) = eval(E1) * eval(E2) / otherwise error!
eval({/ E1 E2}) = eval(E1) / eval(E2) /
eval(id) = error!
eval({with {x E1} E2}) = eval(E2[eval(E1)/x])
eval(FUN) = FUN ; assuming FUN is a function expression
eval({call E1 E2}) = eval(Ef[eval(E2)/x])
if eval(E1)={fun {x} Ef}, otherwise error!
#
(definetype FLANG
[Num Number]
[Add FLANG FLANG]
[Sub FLANG FLANG]
[Mul FLANG FLANG]
[Div FLANG FLANG]
[Id Symbol]
[With Symbol FLANG FLANG]
[Fun Symbol FLANG]
[Call FLANG FLANG])
(: parsesexpr : Sexpr > FLANG)
;; parses sexpressions into FLANGs
(define (parsesexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(symbol: name) (Id name)]
[(cons 'with more)
(match sexpr
[(list 'with (list (symbol: name) named) body)
(With name (parsesexpr named) (parsesexpr body))]
[else (error 'parsesexpr "bad `with' syntax in ~s" sexpr)])]
[(cons 'fun more)
(match sexpr
[(list 'fun (list (symbol: name)) body)
(Fun name (parsesexpr body))]
[else (error 'parsesexpr "bad `fun' syntax in ~s" sexpr)])]
[(list '+ lhs rhs) (Add (parsesexpr lhs) (parsesexpr rhs))]
[(list ' lhs rhs) (Sub (parsesexpr lhs) (parsesexpr rhs))]
[(list '* lhs rhs) (Mul (parsesexpr lhs) (parsesexpr rhs))]
[(list '/ lhs rhs) (Div (parsesexpr lhs) (parsesexpr rhs))]
[(list 'call fun arg)
(Call (parsesexpr fun) (parsesexpr arg))]
[else (error 'parsesexpr "bad syntax in ~s" sexpr)]))
(: parse : String > FLANG)
;; parses a string containing a FLANG expression to a FLANG AST
(define (parse str)
(parsesexpr (string>sexpr str)))
(: subst : FLANG Symbol FLANG > FLANG)
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define (subst expr from to)
(cases expr
[(Num n) expr]
[(Add l r) (Add (subst l from to) (subst r from to))]
[(Sub l r) (Sub (subst l from to) (subst r from to))]
[(Mul l r) (Mul (subst l from to) (subst r from to))]
[(Div l r) (Div (subst l from to) (subst r from to))]
[(Id name) (if (eq? name from) to expr)]
[(With boundid namedexpr boundbody)
(With boundid
(subst namedexpr from to)
(if (eq? boundid from)
boundbody
(subst boundbody from to)))]
[(Call l r) (Call (subst l from to) (subst r from to))]
[(Fun boundid boundbody)
(if (eq? boundid from)
expr
(Fun boundid (subst boundbody from to)))]))
(: Num>number : FLANG > Number)
;; convert a FLANG number to a Racket one
(define (Num>number e)
(cases e
[(Num n) n]
[else (error 'arithop "expected a number, got: ~s" e)]))
(: arithop : (Number Number > Number) FLANG FLANG > FLANG)
;; gets a Racket numeric binary operator, and uses it within a FLANG
;; `Num' wrapper
(define (arithop op val1 val2)
(Num (op (Num>number val1) (Num>number val2))))
(: eval : FLANG > FLANG)
;; evaluates FLANG expressions by reducing them to *expressions* but
;; only expressions that stand for values: only `Fun`s and `Num`s
(define (eval expr)
(cases expr
[(Num n) expr]
[(Add l r) (arithop + (eval l) (eval r))]
[(Sub l r) (arithop  (eval l) (eval r))]
[(Mul l r) (arithop * (eval l) (eval r))]
[(Div l r) (arithop / (eval l) (eval r))]
[(With boundid namedexpr boundbody)
(eval (subst boundbody
boundid
(eval namedexpr)))]
[(Id name) (error 'eval "free identifier: ~s" name)]
[(Fun boundid boundbody) expr]
[(Call funexpr argexpr)
(let ([fval (eval funexpr)])
(cases fval
[(Fun boundid boundbody)
(eval (subst boundbody
boundid
(eval argexpr)))]
[else (error 'eval "`call' expects a function, got: ~s"
fval)]))]))
(: run : String > Number)
;; evaluate a FLANG program contained in a string
(define (run str)
(let ([result (eval (parse str))])
(cases result
[(Num n) n]
[else (error 'run "evaluation returned a nonnumber: ~s"
result)])))
;; tests
(test (run "{call {fun {x} {+ x 1}} 4}")
=> 5)
(test (run "{with {add3 {fun {x} {+ x 3}}}
{call add3 1}}")
=> 4)
(test (run "{with {add3 {fun {x} {+ x 3}}}
{with {add1 {fun {x} {+ x 1}}}
{with {x 3}
{call add1 {call add3 x}}}}}")
=> 7)
(test (run "{with {add {fun {x}
{fun {y}
{+ x y}}}}
{call {call add 8} 9}}")
=> 17)
(test (run "{with {identity {fun {x} x}}
{with {foo {fun {x} {+ x 1}}}
{call {call identity foo} 123}}}")
=> 124)
(test (run "{call {call {fun {x} {call x 1}}
{fun {x} {fun {y} {+ x y}}}}
123}")
=> 124)