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!

  1. 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 don’t 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
    

  2. In problem 6 of assignment 4, you were asked to define a function newinterp which evaluated a term of PCF when given an environment which provided values for all free variables. A solution for this problem can be at http://www.cs.williams.edu/~kim/cs334/s02/Solns/soln4.html

    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.

     


  3. 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].


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


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


  6. Please write the following functions in ML:

    a. A function lookUp which takes a name (a string) and a telephone directory consisting of a list of pairs of strings and integers (representing names and phone numbers), and returns the first pair in the directory corresponding to the name, if there is one. If there is no corresponding name in the directory, please raise an exception called noName.

     

    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 if

    directory = [(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!)


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

    1. Write an ML function, checkBiblio, to take a value of type biblio and return true or false depending on whether or not it satisfies the above DTD specification. Note that order is important in the DTD specification.

      The program that you write should begin with the line:

      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 don’t 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.

    2. Write an ML function , translateBibToHTML that converts a value of type biblio to an HTML file that displays the items in the bibliography nicely in a web page. The following is the expected output from the SXML file given above:

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