[Instructions] [Search] [Current] [Syllabus] [Links] [Handouts] [Outlines] [Assignments] [Labs]

This page may be found online at
`http://www.math.grin.edu/~rebelsky/Courses/CS302/99S/Handouts/examsoln.02.html`

.

*Some time has progressed since I wrote the draft of the exam solutions.
I am no longer sure whether there are any problems. Please let me know
if you observe any.*

In some languages, it's possible to use the input statement in expressions, so that it reads and returns a value, rather than reading a value and storing it in a variable. For example, instead of

read(x);

you would write

x = read();

You can also use `read`

as part of an expression, as in

x = 2 * read() - 5;

Consider the accompanying
description of the semantics of SIMPLE. What changes would we need
to make to the SIMPLE semantics to accommodate this new, no-argument,
`read()`

function? Note that we would also delete the old
`read(I)`

.

After summarizing the changes, write the complete new semantics.

Most of the changes are similar to those we considered in adding an ``assignment expression'' in assignment 3.

- We need to update the abstract syntax to remove the
`read`

statement and add a`read`

expression. - We need to update the type of
`meaningExp`

so that it takes input as a parameter, and ``returns'' the modified input (continuations seem to be the best way to do this). - We probably need an expression continuation domain to simplify this.
- We need to change all the existing definitions of
`meaningExp`

to accomodate the new type. - We need to add a definition for
`meaningExp[[read()]]`

. - We need to change all the uses of
`meaningExp`

to accomodate the new type.

So let's get on with it.

There are no changes to the syntactic domains.

P in Prog L in SL S in Stat E in Exp V in Val I in Ide

We need to drop

Stat => read(I)

and add

Exp => read()

We get the following.

// ProgramsProg => L// Lists of statementsSL => S | S ; L// StatementsStat => I = E | if E then L fi | if E then L0 else L1 fi | while E do L od | write(E)// ExpressionsExp => E_{1}+ E_{2}| E_{1}* E_{2}| E_{1}- E_{2}| E_{1}/ E_{2}| (E) | V | I

We need to add `K`

for expression continuations.
Note that expression continuations are a lot like normal
continuations, except that they take a value as their first
parameter. I've used a shorthand (albeit a completely
correct one) to show this.

n in NNatural Numbersenv in U = Id -> NEnvironmentsinp in I = N*Input (a sequence of numbers)out in O = N*Output (a sequence of numbers)cont in C = U -> I -> OContinuationsecont in K = N -> CExpression continuations

We need to change `meaningExp`

so that it also takes
`I`

and `K`

as parameters. It now simply
returns output, rather than the result value (the continuation
takes care of the rest).

meaningProg : Prog -> I -> O meaningSL : SL -> C-> U -> I -> -> O meaningStat : Stat -> C -> U -> I -> O meaningExp : Exp -> U -> I -> K -> O meaningVal : Val -> N

`meaningProg`

No change, since it doesn't use `meaningExp`

.

meaningProg[[SL]] = meaningSL[[SL]] cleanup basicEnv

`meaningSL`

No change, since it doesn't use `meaningExp`

.

meaningSL[[S;L]] = \cont . \env . \inp . meaningS[[S]] (meaningSL[[L]]] cont) env inp meaningSL[[S]] = meaningS[[S]]

`meaningStat`

We need to delete `meaningStat[[read(I)]]`

, since
there is no longer a `read(I)`

statement.

We need to change `meaningStat[[write(E)]]`

, since
it uses `meaningExp`

.

We need to change `meaningStat[[I = E]]`

, since it
uses `meaningExp`

.

We need to change `meaningStat[[while E do L od]]`

, since
it uses `meaningExp`

.

meaningStat[[write(E)]] = \cont . \env . \inp . meaningExp E env (\n . \env' . \inp' . cons n (cont env' inp')) meaningStat[[I = E]] = \cont . \env . \inp . meaningExp E env (\n . \env' . \inp' . cont (setEnv env' I n) inp' meaningStat [[if E then L_{1}else L_{2}fi]] = \cont . \env . \inp . (meaningExp E env) = 0 -> meaningSL L_{2}cont env inp , meaningSL L_{1}cont env inp meaningStat [[if E then L fi]] = \cont . \env . \inp . (meaningExp E env) = 0 -> cont env inp ; meaningSL L cont env inp meaningStat[[while E do L od]] = F(E,L) s.t. F(E,L) : C -> U -> I -> O F(E,L) cont env inp = meaningExp E env inp (\n . \env' . \inp' . (n == 0) -> cont env' inp' , meaningSL L (\e . \i . F(E,L) cont e i) env' inp'

`meaningExp`

We need to change every one of these equations to accomodate the
new type. We need to change many to accomodate the recursive calls
to `meaningExp`

. We need to add one for `read`

.

The binary operations are relatively straightforward. I've made the decision to evaluate left-to-right, since it's difficult (and not worth my time or yours) to evaluate them in ``arbitrary'' order.

meaningExp [[E_{1}+ E_{2}]] = \env . \inp . \econt . meaningExp E_{1}env inp (\n_{1}. \env_{1}. \inp_{1}. meaningExp E_{2}env_{1}inp_{1}(\n_{1}. \env_{1}. \inp_{1}. econt (n_{1}+ n_{2}) env_{2}inp_{2})) meaningExp [[E_{1}- E_{2}]] = \env . \inp . \econt . meaningExp E_{1}env inp (\n_{1}. \env_{1}. \inp_{1}. meaningExp E_{2}env_{1}inp_{1}(\n_{1}. \env_{1}. \inp_{1}. econt (n_{1}- n_{2}) env_{2}inp_{2})) meaningExp [[E_{1}* E_{2}]] = \env . \inp . \econt . meaningExp E_{1}env inp (\n_{1}. \env_{1}. \inp_{1}. meaningExp E_{2}env_{1}inp_{1}(\n_{1}. \env_{1}. \inp_{1}. econt (n_{1}* n_{2}) env_{2}inp_{2})) meaningExp [[E_{1}/ E_{2}]] = \env . \inp . \econt . meaningExp E_{1}env inp (\n_{1}. \env_{1}. \inp_{1}. meaningExp E_{2}env_{1}inp_{1}(\n_{1}. \env_{1}. \inp_{1}. econt (n_{1}/ n_{2}) env_{2}inp_{2}))

The simple recursive call just ``removes the parentheses'', and doesn't require any other changes. (That's one of the advantages of not listing all the parameters :-)

meaningExp [[(E)]] = meaningExp E

The remaining basic expressions are fairly easy, since they don't involve recursion.

meaningExp [[I]] = \env . \inp . \econt . econt (env I) env inp meaningExp [[V]] = \env . \inp . \econt . econt (meaningVal V) env inp

That leaves us with just the new one. We strip off the front of the input list, and use it as the number parameter.

meaningExp [[read()]] = \env . \inp . \econt . econt (car inp) env (cdr inp)

`meaningVal`

Doesn't change.

Don't change.

// Build a basic environment that assigns 0 to every variable.basicEnv : U basicEnv = \x . 0// A continuation used to ``clean up'' at the end of the program.cleanup : C cleanup = \env . \inp . nil// Set the value associated with an identifier in an environment.setenv : U -> Id -> N -> U setenv env id num = \x . (x == id) -> num , (env id)

Explain the semantics of each of the following standard functions, given on pages 42 and 43 of the Scheme report.

a.

b.

c.

d.

The Fibonacci sequence -- 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ... -- is defined recursively as

- fib(0) = 0
- fib(1) = 1
- fib(n) = fib(n-1) + fib(n-2), for all n > 1

Unfortunately, the natural translation of this into program code leads to an algorithm with exponential running time. Fortunately, it is also possible to write an O(n) implementation iteratively, by keeping track of the previous two values and adding them at each iteration.

Write a O(n) Fibonacci function in FP. You may write this function iteratively or recursively. Make sure that your code is correct, working, and tested.

There are clearly a number of ways to do this problem. I'm going to use a helper function to build the sequence of the first n Fibonacci numbers and then take the last one. The case of 0 is a special one, and is handled specially

{ fib (eq@[id,%0] -> %0; last@fibs) }

Now, how does the helper function work? It will compute the first n Fibonacci numbers by computing the first (n-1) Fibonacci numbers and then adding the last two. The base cases are n=1 (in which case we just use <1>) and n=2 (in which case we just use <1,1>).

{ fibs (eq@[id,%1] -> %<1> ; (eq@[id,%2] -> %<1,1> ;

Now, what about the recursive case? We need to

- do the recursive call, computing
*recursive*fibs@-@[id,%1]

- add the last two elements, computing
*newval*+@[-1,-2]

- and shove the new value on the end
putting it all together, we get
apndr@[

*recursive*,*newval*]{ fibs (eq@[id,%1] -> %<1> ; (eq@[id,%2] -> %<1,1> ; apndr@[id,+@[-1,-2]]@fibs@-@[id,%1])) }

As many of you have noted, FP uses a somewhat different technique for describing the semantics of built-in functions and functional forms. In this question, you will further explore that technique.

Suppose we decided to add a `case`

functional form to FP. Case
has the form

case p f_{1}f_{2}... f_{n}

This is a true functional form. All arguments are functions, and it
creates a new function. The informal meaning of `case`

is
``apply `p`

to the argument; if the result is 1, apply
`f`

to the argument; if
the result is 2, apply f_{1}_{2}; and so on and so forth''.

Write a formal definition of this new `case`

functional form,
using the same notation and care that Backus uses.

**History**

- Created Wednesday, March 10, 1999.
- A few minor changes on Friday, March 12, 1999.
- A few more details on Monday, May 17, 1999.

[Instructions] [Search] [Current] [Syllabus] [Links] [Handouts] [Outlines] [Assignments] [Labs]

**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.

This page may be found at http://www.math.grin.edu/~rebelsky/Courses/CS302/99S/Handouts/examsoln.02.html

Source text last modified Mon May 17 10:11:48 1999.

This page generated on Mon May 17 10:18:52 1999 by SiteWeaver. Validate this page's HTML.

Contact our webmaster at rebelsky@math.grin.edu