Programming Languages (CSC-302 98S)

[Instructions] [Search] [Current] [Changes] [Syllabus] [Handouts] [Outlines] [Assignments]

# Outline of Class 38: Semantics of Scheme

Held: Wednesday, May 6, 1998

• I should have homework six graded for Friday.
• The final is next Monday. It is cumulative. A review sheet will be ready on Friday, and we'll spend at least part of Friday's class on review.

## Denotational Semantics of SIMPLE

• Let's develop a denotational semantics for SIMPLE. Our semantics will need to accommodate the various utterances in the language.
• We begin with the syntactic domains. These correspond to the nonterminals of our grammar.
```V in Val                       Numeric constants
I in Id                        Variables
E in Exp                       Expressions
S in Sta                       Statements
L in SL                        Statement Lists
P in Prog                      Programs
```

• We continue with an abstract syntax
```Prog ::= L
SL ::= S
|  S ; L
Stat ::= I = E
|  if E then L fi
|  if E then L0 else L1 fi
|  while E do L od
|  write(E)
Exp ::= E0 + E1
|  E0 * E1
|  E0 - E1
|  E0 / E1
|  (E)
|  V
|  I
```

• 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.
```meaningProg[[SL]] = meaningSL[[SL]] cleanup basicEnv
basicEnv : U
basicEnv = \x . undefined
cleanup = \env . \inp . nil
```

• Note that I'm using `\var . body` for `lambda var . body`
• Where's the input? It's hidden, because everything is curried. We could just as easily have written
```meaningProg[[SL]] = \inp . meaningSL[[SL]] cleanup basicEnv inp
```

• What is the meaning of a statement list? It depends on whether it's a single statement or an actual list. In the first case, the meaning is simply the output of the statement. input and environment.)
```meaningSL[[S]] =
\cont . \env . \inp .  meaningS[[S]] env inp cont
```

• Note that if I'd chosen a better order for the arguments to the statementlist meaning function, I might have been able to write a simpler definition.
• What is the meaning of a statement list with multiple statements? It's fairly simpmle
```meaningSL[[S;L]] =
\cont . \env . \inp . meaningS[[S]] env inp meaningSL[[L]]
```

• Now we can worry about the individual statements.
• What is the meaning of input? An update to the environment. Note that to update the environment, we'll need a conditional and some list selection operations.
• We'll use the McCarthy conditional, `t -> a, b`, which means "if t then a else b".
• We'll just use `car` and `cdr`.
```meaningStat[[read(I)]] =
\env . \inp . \cont .
cont (setenv env I (car inp)) (cdr inp)
setenv : U -> Id -> N -> U
setenv env id num =
\x . (x == id) -> num , (env id)
```

• What is the meaning of output? We'll assume there is a convenient `cons` operation. (See the Scheme specification for a more formal version.)
```meaningStat[[write(E)]] =
\env . \inp . \cont .
cons (meaningExp[[E]] env) (cont env inp)
```

• Assignment is similar to a combination of the two.
```meaningStat[[I = E]] =
\env . \inp . \cont .
cont (setenv env I (meaningExp[[E]] env)) inp
```

• 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.]
• So,
```meaningStat[[while E do L od]] = F(E,L) s.t.
F(E,L) :: U -> I -> C -> O
F(E,L) env inp cont =
((meaningExp[[E]] env) == 0) -> cont env inp,
meaningSL(L) env inp (\e . \i . F(E,L) e i cont)
```

## The Denotational Semantics of Scheme

• As you can tell from reading the Scheme report, the formal semantics of Scheme is quite small.
• This is partially because it's an elegant set of definitions.
• This is partially because more complex Scheme builtins can be automatically translated to Scheme primitives, so we don't need a large set of primitives.
• The semantics is designed for people used to reading semantics and thinking functionally. Novices may find that it takes awhile to plow through it.
• At the same time, it is useful as a begnning point in reading "real" semantics.
• Reading the section on semantics (section 7.2 in the Revised (5) report), you will note that it contains
• A description of the notation used (or selected parts of that notation; lambdas aren't mentioned even though they are used).
• A short commentary on general issues intented to introduce the definition.
• An abstract syntax
• A set of domain equations defining the primary domains over which the semantic functions operate.
• A list of types for semantic functions.
• Definitions of the semantic functions.
• Definitions of "helper" functions used to define the semantic functions.

### Notation

• 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).
• Elsewhere in the section, you will see lambdas used frequently.
• These are curried lambdas, so "lambda x y . whatever" is shorthand for "lambda x . lambda y . whatever".
• You may observe that the particular symbols used for variables are important. In particular, the name of a variable indicates its type (not a traditional design in languages, but useful).
• You should also observe that different fonts and styles are used to indicate different roles.
• Roman words are used for syntactic domains.
• Capital Greek letters are used for variables reperesenting elements of those domains).
• Monospace words are used for syntactic elements.
• Monospace letters are used for semantic domains.
• Lowercase Greek letters are used for elements of semantic domains.
• Script letters are used for semantic functions.
• Script words are used for the helper functions.

### Abstract Syntax

• The abstract syntax of Scheme should be somewhat self-evident.
• There are only four "kinds" of things in Scheme programs: constants, identifiers, expressions, and commands.
• In fact, commands and expressions are more-or-less the same thing.
• There are only a few kinds of expressions. They are
• Constants
• Identifiers
• Application of an expressoin to one or more expressions
• Three kinds of lambda abstractions
• Two kinds of conditionals
• One side-effecting operator
• What kinds of lambdas are there?
• Functions with a particular number of arguments.
• Functions written to handle an arbitrary number of arguments.
• Functions in which the aguments are contained in the body.
• Note that each lambda abstraction permits a sequence of "commands" before ending with an expression that represents the value of the lambda expression.
• You might want to note that the abstract syntax is ambiguious. This is because "they details are in the concrete syntax". In particular, parsing is treated as a separate issue.

On to Wrapup
Back to Introduction to Semantics
Outlines: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Current position in syllabus

[Instructions] [Search] [Current] [Changes] [Syllabus] [Handouts] [Outlines] [Assignments]

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.