Take-Home Midterm
CS334, Spring 2002
Instructions: This exam is due at 2:15 p.m. on Friday, April 5! You may consult your notes, all documents on the course web page or any document in the http://www.cs.williams.edu/~kim/cs334/s02 subdirectory, all homework you turned in, the texts, any papers handed out in class, the texts on the reserve shelf in the library, and the instructor. You may also use the Dells in order to test your programming solutions. You may not talk with anyone aside from me about any aspect of the exam, or consult any other materials (including other material in the library or your classmates' notes, their homework solutions, other material on the web, etc.). Please do not forget to answer any of the parts of the questions, and give complete (but not redundant) answers. The questions are similar in spirit to those given earlier in homework assignments. Please turn in a paper copy of your exam as well as electronic copies of any programs you have written using the turnin program.
Good luck and don't hesitate to ask if you have any questions!
a. In lecture 11, I provided an operational semantics for while loops:
(b, ev, s) >> (false, s') -------------------------- (while b do C, ev, s) >> s' (b, ev, s) >> (true, s') (C, ev, s') >> s'' (while b do C, ev, s'') >> s''' ---------------------------------------------- (while b do C, ev, s) >> s'''
where ev is an environment and s is a store. Please provide similar
rules for "repeat ... until" loops. The resulting semantics should be the
same as for "repeat..until" loops in Pascal. That is, when "repeat S
until B" is executed, it first executes S. If B is false afterward,
then S is executed again, this continues until B is true after the
execution of S.
(S, ev, s) >> s', (B, ev, s') >> (true, s'') --------------------------------------------- (repeat S until B, ev, s) >> s'' (S, ev, s) >> s', (B, ev, s') >> (false, s'') (repeat S until B, ev, s'') >> s''' ----------------------------------------------- (while b do C, ev, s) >> s'''
b. While we discussed the semantics of various commands in that lecture, we never discussed how to process declarations. Please write a rule that would process the following declaration:
var vble = exp;
where vble is a variable name, and exp is an expression. [Our
language is untyped, so we dont include a type specification. The
intent is to introduce a variable and initialize it.] Write the rule in
the same form as the other rules.
(exp, ev', s) >> (v,s') where ev' = ev[vble := newLoc] ------------------------------------------------------ (var vble = exp, ev, s) >> (ev', s'[newLoc := v]) where newLoc is not in dom s
That problem used static scoping to interpret the meaning of terms (see the discussion between parts a and b of that problem). How must the interpreter be modified in order to provide for dynamic scoping? (Hint: Look at an example like that of problem 5a of assignment 4 and figure out what environment you need to use when functions are applied to their arguments.) Please include complete code for your new interpreter (you are welcome to start with my code). Include an explanation of why the changes that you made support dynamic scoping. You will only receive partial credit if the explanation is not included.
use "parsePCF.ml"; datatype value = NUM of int | BOOL of bool | SUCC | PRED | ISZERO | CLOSURE of (string * term) | THUNK of term | ERROR of string; withtype env = (string * value) list; fun update environ nustr nuval:env = (nustr,nuval)::environ; fun getVal id [] = ERROR (id^"not in environment",NUM 0) | getVal id ((id2,val2)::rest) = if (id = id2) then val2 else getVal id rest; fun newinterp (AST_NUM(n)) env = NUM (n) | newinterp (AST_ID(id)) env = let fun process(THUNK(tm)) = newinterp tm env | process(other) = other in process(getVal id env) end | newinterp (AST_BOOL(bval)) env = BOOL(bval) | newinterp (AST_FUN(param,body)) env = CLOSURE(param,body) | newinterp (AST_SUCC) env = SUCC | newinterp (AST_PRED) env = PRED | newinterp (AST_ISZERO) env = ISZERO | newinterp (AST_ERROR s) env = ERROR ("parse error:"^s) | newinterp (AST_REC(name,body)) env = ERROR "recursion omitted" | newinterp (AST_IF(test,yesval,noval)) env = let val testval = newinterp test env; fun trueval(BOOL(true)) = true | trueval(x) = false; fun falseval(BOOL(false)) = true | falseval(x) = false; in if trueval(testval) then newinterp yesval env else if falseval(testval) then newinterp noval env else ERROR "bad if" end | newinterp (AST_APP(func,arg)) env = let val evalfunc = newinterp func env; val evalarg = newinterp arg env; fun eval(SUCC,NUM(n)) = NUM(n+1) | eval(PRED,NUM(n)) = if n > 0 then NUM(n-1) else NUM 0 | eval(ISZERO,NUM(n)) = if n = 0 then BOOL(true) else BOOL(false) | eval(CLOSURE(param,body),arg) = let val nuenv = update env param arg in newinterp body nuenv end | eval(fst,snd) = ERROR "bad app" in eval(evalfunc,evalarg) end;
Adding recursion is tricky because must remember how to make the recursive call while not keeping other parts of the environment around.
Please do problem 6.38 on page 6-53 of Louden. Be sure to answer
all parts of the question and to show in detail how ML came up with the
type of f.
The most general type is "a -> bool, yet ML gives bool ->
bool. The proof is given either with the syntax trees in the text or with
equations [omitted here].
Macro-expansion of procedure calls involves textually substituting the actual parameters in a procedure call for the formal parameters in the text of the procedure, and then textually substituting in the resulting procedure body at the location of the call. A programming language text I was reading states that this gives exactly the same result as dynamic scoping. This is almost correct, but not quite. Why is this not quite right? Under what conditions is it correct? Please explain why.
The problem arises when a local variable "captures" an actual parameter. Otherwise, this method does a good job of handling call-by-name parameter passing with dynamic scoping. Here is an example of the problem:
int x = 17; void p(int y) { int x = 0; System.out.println(x + y); } void main() { p(x); }
This prints 17 with dynamic (and static) scoping. If this is expanded out, get
int x = 17; void main() { { int x = 0; System.out.println(x + x); } }
This prints out 0.
The required parameter passing method question:
a) Show the values printed by this program when the parameters are
passed by each of
i) call-by-value, ii) call-by-reference, and iii) call-by-value-result:
Program test; var a: integer; procedure P(b:integer); begin b:= b+1; print(b,a) end; begin a:=1; P(a); print(a) end.
i. value: 2,1,1 ii. Reference: 2,2,2 iii. Value-result: 2,1,2
b) In the following procedure the parameters x and index are call-by-name, while j and h are call-by-value.
procedure P(name x, index: integer; j, h: integer); var m: integer; begin for index := j to h do begin m := 1; x := 0 end end;
Suppose i, k, and m are all integer variables defined in the main program, while a and b are integer arrays with subscripts in the range from 1 to 100.
What is the result of the following calls?
i. P(a[i], i, 1, 100)
a[1..100] all set to 0
ii. P(b[k * k], k, 1, 10)?
b[1,4,9,
,100] all set to 0, rest untouched
iii. P(a[m],m,1,100)?
same as i. because NOT call by text
Please write the following functions in ML:
a. A function
exception noName; fun lookUp name [] = raise noName | lookUp name ((first, number)::rest) = if name = first then (first, number) else (lookUp name rest);
b. Please write a function
getPhoneNums which takes a list of names, lookUpNames, and a directory (as in a above) and returns a pair (phonelist,badNames), where phonelist is a list of pairs of names and numbers corresponding to those in lookUpNames which exist in the directory and badNames is a list of all of those names which did not appear in the directory. For example ifdirectory = [(Kim,2273),(Fatma,2311),(Sally,1234)]
,then
getPhoneNums [Kim,Bill,Jane,Fatma] directory should return([(Kim,2273),(Fatma, 2311)],[Bill,Jane])
This function should use the function
lookUp defined in part a, and needs to catch the exception noName raised by that function.fun getPhoneNums [] directory = ([],[]) | getPhoneNums (name1::rest) directory = let val (phoneList, badNames) = getPhoneNums rest directory in ((lookUp name1 directory)::phoneList, badNames) handle noName => (phoneList, (name1::badNames)) end;
(Thanks to Caroline from whose solution this was adapted!)
In this question, the goal is to teach you something about XML as well as testing your knowledge of ML programming. As a result, the write-up will be a little long.
In lecture 7, we discussed how to parse SXML (simplified XML)
code. For this problem, I would like you to take an SXML representation
of a bibliography, verify it, and translate it into a form that would
display nicely on a web page.
As mentioned in class, XML differs from HTML by specifying the semantics
of structured data as opposed to the layout. DTD files specify the
structure of data, so that XML files can be checked for static semantic
correctness. One can think of the DTD files as specifying the static
types for XML files. The following is a DTD file specifying the correct
structure of files representing a bibliography:
<!DOCTYPE Biblio [
<! ELEMENT Biblio (Entry*)>
<! ELEMENT Entry (Article | Book)>
<! ELEMENT Article (RefName Author+ Title Journal Volume? Number? Year Pages?)>
<! ELEMENT Book (RefName Author+ Title Publisher Volume? Year)>
<! ELEMENT RefName (#PCDATA)>
<! ELEMENT Author (#PCDATA)>
<! ELEMENT Title (#PCDATA)>
<! ELEMENT BookTitle (#PCDATA)>
<! ELEMENT Year (#PCDATA)>
<! ELEMENT Volume (#PCDATA)>
<! ELEMENT Number (#PCDATA)>
<! ELEMENT Pages (#PCDATA)>
<! ELEMENT Journal (#PCDATA)>
<! ELEMENT Publisher (#PCDATA)>
]>
The DTD file specifies that a Biblio file is a sequence of 0 or
more entries, where each entry is an article or book ("|" means
"or"). An article consists of a RefName (a unique name to look
up entries by), followed by 1 or more authors ("+" means one or
more), then a title, a journal, an optional volume ("?" means it
is an optional entry), an optional number, a year, and an optional pages
entry. Notice that order is important. For example, an article entry is
not legal if the author comes after the title. A book is specified
similarly in the "<!ELEMENT Book(
)>" specification.
Each of the components of an Article or Book is a string that is
what is meant by the "#PCDATA" entries specifying their
contents.
We could approximate this in a more familiar way with a context-free
grammar as follows:
Biblio ::= Entry* Entry ::= Article | Book Article ::= RefName Author+ Title Journal Volume? Number? Year Pages? Book ::= RefName Author+ Title Publisher Volume? Year
You are to write two programs that take as input an SXML file and
first check it for soundness with respect to the above DTD file, and then
write another program to convert it to an HTML file suitable for
displaying in a web page. I will provide programs to parse the SXML into
an easier form to work with. You can use these in your programs.
We begin by providing sample SXML code that is legal according to the DTD
specification given above:
<bibliography>
<ARTICLE>
<REFNAME>CSEdThoughts</REFNAME>
<Author>Kim B. Bruce</AUTHOR>
<Title>Thoughts on Computer Science Education</Title>
<Journal>ACM Computing Surveys</Journal>
<Volume>28</Volume>
<Number>4es</Number>
<Year>1996</year>
<Pages>93-es</Pages>
</ARTICLE>
<BOOK>
<REFNAME>AbCardBook</REFNAME>
<Author>Martin Abadi</AUTHOR>
<AUTHOR>Luca Cardelli</AUTHOR>
<Title>A Theory of Objects</TITLE>
<Publisher>Springer-Verlag</Publisher>
<Year>1996</YEAR>
</BOOK>
<ARTICLE>
<REFNAME>CompObjJ</REFNAME>
<Author>Kim B. Bruce</AUTHOR>
<Author>Luca Cardelli</AUTHOR>
<Author>Benjamin C. Pierce</AUTHOR>
<Title>Comparing Object Encodings</Title>
<JOURNAL>Information and Computation</JOURNAL>
<Volume>155</Volume>
<Year>1999</year>
<Pages>108-133</Pages>
</ARTICLE>
<BOOK>
<REFNAME>FOOLBook</REFNAME>
<Author>Kim B. Bruce</AUTHOR>
<Title>Foundations of Object-Oriented Languages: Types and Semantics</Title>
<Publisher>MIT Press</PUBLISHER>
<Year>2002</year>
</BOOK>
<ARTICLE>
<REFNAME>BinMeth</REFNAME>
<Author>Kim B. Bruce</AUTHOR>
<Author>Luca Cardelli</AUTHOR>
<Author>Giuseppe Castagna</AUTHOR>
<Author>The Hopkins Objects Group</AUTHOR>
<Author>Gary T. Leavens</AUTHOR>
<Author>Benjamin C. Pierce</AUTHOR>
<Title>On binary methods</Title>
<JOURNAL>Theory and Practice of Object Systems</JOURNAL>
<Volume>1</Volume>
<NUMBER>3</NUMBER>
<Year>1995</year>
<Pages>221-242</Pages>
</ARTICLE>
</bibliography>
This file contains bibliographic entries for
5 items: 3 articles and 2 books. As with all XML files, tags indicate
the semantic structure, with opening and closing tags differing only by a
"/". Notice that capitalization of tags is irrelevant.
This data conforms to the DTD definition as it is a sequence of zero or
more entries, each of which is an article or book. Each of the article
and book entries is legal because it consists of the components specified
by the DTD. For example, the second entry is a legal book because it
consists of a refname item, two authors (1 or more are required), a title,
publisher, and year. The optional volume is not included.
The programs I will provide you with will parse this file into a value of
ML datatype biblio where:
datatype item = RefName of string | Author of string | Title of string | BookTitle of string | Year of string | Volume of string | Number of string | Pages of string | Journal of string | Editor of string | Publisher of string; datatype biblioEntry = BookEntry of item list | ArticleEntry of item list; datatype biblio = Biblio of biblioEntry list;
You should have no difficulty seeing how the above file would be
translated, but feel free to run my program on it to see exactly how it
would look.
use "biblioTypes.ml";
That program will itself use the file "parseXML.ml". Both of these are available on-line in directory ~kim/home/cs334stuff/XMLstarter. Executing
processBiblio (parsefile fileName))
will parse the SXML code in the file named fileName (it is a string, so dont forget the quotes when you put in an actual name) and return an element of type biblio. Your function will take that value and determine whether or not it is legal.
Finally, write a function, checkBiblioFile, that takes a filename and returns true or false depending on whether or not it is legal according to the DTD specification. Your program should use my functions processBiblio and parsefile. If the input file is not legal SXML or includes tags different from those specified above, it will throw an exception. If an exception is thrown, you should catch it and return false.
Click here for solution.
<HTML>
<H2>BIBLIOGRAPHY</H2>
<OL>
<LI>
<I>Kim B. Bruce</I>,
<B>Thoughts on Computer Science Education</B>,
<U>ACM Computing Surveys</U>,
vol. 28,
no. 4es,
1996,
pages 93-es.
<LI>
<I>Martin Abadi, Luca Cardelli</I>,
<B>A Theory of Objects</B>,
Springer-Verlag,
1996.
<LI>
<I>Kim B. Bruce, Luca Cardelli, Benjamin C. Pierce</I>,
<B>Comparing Object Encodings</B>,
<U>Information and Computation</U>,
vol. 155,
1999,
pages 108-133.
<LI>
<I>Kim B. Bruce</I>,
<B>Foundations of Object-Oriented Languages: Types and Semantics</B>,
MIT Press,
2002.
<LI>
<I>Kim B. Bruce, Luca Cardelli, Giuseppe Castagna, The Hopkins Objects Group, Gary T. Leavens, Benjamin C. Pierce</I>,
<B>On binary methods</B>,
<U>Theory and Practice of Object Systems</U>,
vol. 1,
no. 3,
1995,
pages 221-242.
</OL>
</HTML>
Notice that the entire file is surrounded by pairs of HTML and OL tags (start and end), as well as having the "BIBLIOGRAPHY" title. Each individual item is started with <LI>. Individual items are separated by commas, with a period at the end of an entry. The authors names are separated by commas and are enclosed (as a group) in I tags, causing them to be displayed in italics. The titles are enclosed in B tags (for bold), while the journal names are surrounded by U tags (for underlining). If you copy this text into a text file and open it in a browser, you will see what it looks like when displayed. Notice that the strings "vol.", "no.", and "pages" are inserted where appropriate in the output (i.e., they were not in the input).
New lines can be started by inserting "\n" into the output and tabs are inserted with "\t". These will not show up properly unless you use the print command! Thus I would like you also to write a function translateBibFileToHTML that reads in a filename and prints the string returned by translateBibToHTML. That is, the definition will look something like:
fun translateBibFileToHTML filename = print (translateBibToHTML( ));
If the input value is illegal, you should throw an exception (either reuse my illegalTerm exception or declare your own.
This question is long, but I hope you will learn something from it, as the kind of thing you are doing here is quite common with XML (though there are tools and even a special functional language, XSLT, designed to help with it). The key is to write lots and lots of small specialized functions, as we did with parsers, as these programs have some of the same flavor as parsers (though you will not need to worry about FIRST and FOLLOW functions).
Click here for solution.