[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.
read
statement and add a read expression.
meaningExp so that it
takes input as a parameter, and ``returns'' the modified input
(continuations seem to be the best way to do this).
meaningExp to accomodate the new type.
meaningExp[[read()]].
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.
// Programs
Prog => L
// Lists of statements
SL => S
| S ; L
// Statements
Stat => I = E
| if E then L fi
| if E then L0 else L1 fi
| while E do L od
| write(E)
// Expressions
Exp => E1 + E2
| E1 * E2
| E1 - E2
| E1 / E2
| (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 N Natural Numbers env in U = Id -> N Environments inp in I = N* Input (a sequence of numbers) out in O = N* Output (a sequence of numbers) cont in C = U -> I -> O Continuations econt in K = N -> C Expression 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 L1 else L2 fi]] =
\cont . \env . \inp .
(meaningExp E env) = 0 -> meaningSL L2 cont env inp
, meaningSL L1 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 [[E1 + E2]] = \env . \inp . \econt . meaningExp E1 env inp (\n1 . \env1 . \inp1 . meaningExp E2 env1 inp1 (\n1 . \env1 . \inp1 . econt (n1 + n2) env2 inp2)) meaningExp [[E1 - E2]] = \env . \inp . \econt . meaningExp E1 env inp (\n1 . \env1 . \inp1 . meaningExp E2 env1 inp1 (\n1 . \env1 . \inp1 . econt (n1 - n2) env2 inp2)) meaningExp [[E1 * E2]] = \env . \inp . \econt . meaningExp E1 env inp (\n1 . \env1 . \inp1 . meaningExp E2 env1 inp1 (\n1 . \env1 . \inp1 . econt (n1 * n2) env2 inp2)) meaningExp [[E1 / E2]] = \env . \inp . \econt . meaningExp E1 env inp (\n1 . \env1 . \inp1 . meaningExp E2 env1 inp1 (\n1 . \env1 . \inp1 . econt (n1 / n2) env2 inp2))
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)
meaningValDoesn'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
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
fibs@-@[id,%1]
+@[-1,-2]
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 f1 f2 ... fn
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
f1 to the argument; if
the result is 2, apply f2; 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
[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