Today, we mainly discussed functions.

Recall also from last time:

**Extensional equivalence**.

Extensional
equivalence is an equivalence relation on well-typed SML expressions,
relating well-typed expressions of the same type.

Two expressions `e` and `e'` of the same
(nonfunction) type are *extensionally equivalent*, written
`e ≅ e'`, whenever one of the following is true: (i)
evaluation of `e` produces the same value as does evaluation of
`e'`, or (ii) evaluation of `e` raises the same
exception as does evaluation of `e'`, or (iii) evaluation of
`e` and evaluation of `e'` both loop forever.

We further say that two functions `f : t -> t'`
and `g : t -> t'` of the same type are extensionally
equivalent whenever `f(v)` and `g(w)` are
extensionally equivalent for all extensionally equivalent argument
values `v` and `w` of type `t`. Formally,
`f ≅ g` if and only if `f(v) ≅
g(w)` for all values `v : t` and
`w : t` for which `v ≅ w`.

**Totality**.

We say that a function `f :
t -> t'` is *total* if and only if
`f(v)` reduces to a value for every possible
argument value `v` of type `t`.

Frequently, a proof of correctness may require establishing that some
expression reduces to a value. In order to accomplish that, it may be
useful to know that some function is total.

For instance, if one
wants to establish that the expression `x + f(y)`
reduces to a value, one approach is to show that
`x` and `y` reduce to values and
that `f` is a total function (possibly also that
`+` is total, though we usually take that for
granted in this course).

Totality is an important concept, at the
core of what it means to actually perform computations. Many
mathematical functions are not computable by total functions.

**Functions as values.**

A function value consists of an *anonymous lambda expression* along with a (possibly empty) environment of bindings for any nonlocal variables that appear in the body of the function.
The combination of a lambda expression and an environment is called a *closure*.

Example 1: The anonymous lambda expression `(fn (x:int) =>
x*x)` is a function that squares its argument. (The only
nonlocal variable here is the symbol `*`. Technically, the
environment includes a binding of an internal multiplication function
to this symbol. For simplicity, we generally do not specify bindings
of such built-in functions in this course.)

Example 2: ` [3.14159265358979/pi](fn (r:real) => pi*r*r)` is an environment and an anonymous function that together provide a function for computing the area of a disk of radius `r`.

**NOTE:** A lambda expression (plus any bindings of nonlocal
variables) is a value.
A value is a value; one cannot reduce a value further.

So one would **not** say that
`[2/s, 3/r](fn (x:int) => (s+r)*x)` *reduces to* `(fn (x:int) => 5*x)`.

However, it is true that these two function values are *extensionally equivalent*,
i.e., `[2/s, 3/r](fn (x:int) => (s+r)*x) ≅ (fn (x:int) => 5*x)`.

Why? Because one may make the extensionally equivalent
*substitutions* of `2` for `s` and `3` for
`r` in the lambda expression `(fn (x:int) => (s+r)*x)`
to obtain the extensionally equivalent lambda expression
`(fn (x:int) => 5*x)` and then (by referential transparency)
one may use this simpler lambda expression in place of the
original.

**Also:** When SML prints a function value in the
REPL, it will merely print `fn` (plus the type of
the function), not all the internal details of the closure. Only in
proofs or similar reasoning do we use the written representation shown
above. And of course, you can't directly write a closure inline in
code. If you want bindings in the environment, you have to create
those using declarations. However, you *can* write anonymous
lambda expressions inline in your code, as in
`(fn (x:int) => x*x)(7)`, for instance.

We discussed function application. In order to evaluate `e2 e1`:

- Reduce
`e2`to a function value`f`of the form`fn(x:t)=>e`. - Reduce
`e1`to a value`v`. - Locally extend the environment that
*existed at the time of definition*of`f`with a binding of value`v`to the variable`x`. - Evaluate the body of
`f`in the resulting environment.

Notationally, we might write`[v/x]e`for this evaluation, with the relevant prior environment clear from lexical scoping.

Example: The declaration

fun square (x:int) : int = x * xproduces a binding of a function value to the variable

square(3+4) ==> (fn(x:int) => x*x)(3+4) ==> (fn(x:int) => x*x)(7) ==> [7/x]x*x ==> 7*7 ==> 49

See also again the evaluation notes from the previous lecture.

Side comment: In class we thought of a function closure as consisting of a lambda expression and the environment in effect at the time of definition of the function. That is slightly different than the definition given above, since the environment at the time of definition may contain more bindings than are necessary to resolve the values of any nonlocal variables appearing in the body of the function. However, the two definitions amount to the same thing operationally, since those extra bindings never matter.

**Five-Step Methodology.**

As a reminder, in assignments, please use the 5-step methodology for writing functions:

- In the first line of comments, write the name and type of the function.
- In the second line of comments, specify via a
`REQUIRES`clause any assumptions about the arguments passed to the function. - In the third line of comments, specify via an
`ENSURES`clause what the function computes (what it returns). - Implement the function.
- Test your code.

**Patterns.**

We discussed patterns, and their use in clausal function definitions
and in `case` expressions.

These concepts are discussed further in the evaluation notes from the last
lecture.

- Extensional Equivalence
- Functions
- Functions as values
- Anonymous lambda expression
- Closure
- Clausal function definitions
- Pattern matching
- 5-Step Methodology

Looking ahead, here is a short introduction to lists.

For HW1 all you need to know is that `[n]` is a list consisting
of the single integer `n` and that you can add a new element
`x` onto an existing list `L` using the "cons" operator
`::`, by writing `x::L`.

Example: `3::[1,4]` produces the list `[3,1,4]`,
of type `int list`.

(It also turns out that one can pattern match on the structure of a
list. Take a look at the `case` expression in the document
linked above.)