Note that this is somewhat different than our traditional syntax.
This is an abstract syntax and assumes that the details (such as
associativity) are worked out in the concrete syntax. Note also
that we use variables on the right hand side and sets on the left.

We'll need a meaning function for each of the syntactic domains.
We'll call these meaningProg, meaningStat,
meaningExp, and meaningSL.

What are the semantic domains we'll need? Certainly input (a list of
numbers), output (a list of numbers and "error"s), the environment
(a map from identifiers to numbers or "undefined"), and perhaps some
other things.

N Natural numbers
U = Id -> N Environments
I = N* Input
O = N* Output

We certainly need to consider the appropriate type of our functions.

What is the type of an evaluated program? A program should be
a function from input to output.

meaningProg :: Prog -> I -> O

What is the type of an evaluated statement? That might be a little
bit harder. In order to evaluate a statement, we need the environment
and may need the input. After evaluating a statement, we may have
affected environment, output, and input.

How do we "pass them back" for the next statement?

We could return a triplet.

We could evaluate the next statement in the updated environment
and input.

We'll try the second. This means that the meaning functions for
statements must take "something" as a third parameter. Hmmm ... that
thing is "rest of program", which seems awfully like "continuation".

C = U -> I -> O

Now let's again consider the type of meaningStat. To determine
the meaning of a statement, we need its environment, input, and
continuation. The result is output.

meaningStat : Stat -> U -> I -> C -> O

Okay, what about statement lists? From our abstract and concrete syntax,
we know that a statement list can be a statement or a statement
followed by a statement list. They can also appear in while loops and
conditionals. We also know that statement lists
relate to programs. Since they'll need to read input and write output
using an environment, perhaps with

meaningSL : SL -> C-> U -> I -> -> O

Why did I change the place of the continuation? Just for variety.

We're left with expressions. What is the type of
meaningExp? It might be useful to specify what happens
with the expression, or it might be useful just to give a value. In
either case, we need the environment (since the expression may contain
variables). Rather than using continuations, we'll just have
the meaning of an expression be a value.

meaningExp : Exp -> U -> N

Note that we need an environment so that we can look up identifiers.

We are now ready to write our semantic functions.

The meaning of a program is the meaning of the corresponding statement
list when run on the basic environment.

What about loops? Loops can be more complicated for a number of
reasons.

The definition is even more recursive than most.

Not all loops terminate.

We'll handle recursion the "quick and dirty" way. We're describing
a function, not defining it. Any function that meets our criteria
is acceptable (although we prefer the least such function).

Nontermination is a more subtle issue. In effect, a program that
doesn't terminate doesn't meet our requirements for the meaning
function (generating a list of numbers). What do we do? We should
update our requirements (including, perhaps, cons) so that
"nonterminating" is a legal result. [This is left as an exercise
for the reader.]

There are a number of notations we must concern ourselves with in the
Scheme report.

There is the notation introduced at the beginning of section 7.2.

There are many sequence-based operations.
This suggests that much of the definition of Scheme will be sequence-based
(as you might expect). The semantics will take advantage of sequence
creation, destruction (select elements and removing initial elemnts),
length, and concatenation.

In addition, we will use conditionals (a frequently needed device)(
and substitution.

We will also use injection (moving from subset to superset) and
project (from superset to subset).