Sample examination questions

Course links

1. Give an example of a function from ASCII character strings to ASCII character strings that has infinitely many fixed points.
2. In the Pascal programming language, a repeat-statement consists of the keyword repeat, one or more statements, the keyword until, and a Boolean expression. Any two otherwise adjacent statements between repeat and until must be separated by a semicolon. Taking the <statement> and <Boolean expression> categories as given, write a description of the syntax of repeat-statements in Pascal in extended Backus-Naur form.
3. Describe the difference between eager and lazy evaluation, first from the programmer's point of view, then from the point of view of the implementer of the language.
4. In the object-oriented language developed in section 9.3 of the textbook, what identifiers may occur as free variables in the body of a method declaration?
5. Describe the steps that a type checker would go through in checking the type of a let-expression in the CHECKED language of section 7.1.
6. Suppose that we wanted to add to the LETREC language a when-expression, with the syntax
when <expression> <expression>

A when-expression has the value of its second subexpression if the value of its first subexpression is the Boolean value true; otherwise, the value of the when-expression is the Boolean value false.

Which, if either, of the subexpressions of a when-expression are in operand position? Which, if either, are in tail position?

7. Write a specification (similar to those in section 5.1 of the textook) for each new variant of the continuation data type that would be needed in order to add when-expressions to the continuation-passing interpreter for LETREC developed there.
8. Suppose that we wanted each thread in a multithreaded computation to have a priority --an integer indicating how important and time-critical the thread is -- and that we wanted higher-priority threads always to run before lower-priority ones, while threads of equal priority trade off like all the threads in the implementation in section 5.5 of the textbook. What would we have to change in the language and implementation of THREADS in order to achieve this?
9. Convert the following LETREC program to continuation-passing style, using the algorithm presented in chapter 6 of the textbook.
letrec iterate(n) = proc (f)
                     proc (b)
                      if zero?(n)
                      then b
                      else (f (((iterate -(n, 1)) f) b))
in (((iterate 5) proc(n) -(n, -(0, n))) 7)
10. In a language that uses dynamic scope, how is the binding of an identifier that occurs free in a function definition determined at run time?
11. I/O is notoriously one of the most difficult parts of a language to design; there seems to be no approach that pleases everyone. Here are three approaches to the problem of outputting values of various data types. If you were designing a general-purpose programming language, which of these approaches would you be most likely to choose, and why?

(1) In SNOBOL4, there is a predefined identifier OUTPUT that is treated as a write-only reference. Attempting to determine the value of OUTPUT is a run-time error; however, OUTPUT can be used in any other context that requires a reference, such as the left-hand side of an assignment. When a value is assigned to OUTPUT, it is coerced to the STRING data type (if this is not possible, a run-time error occurs) and the result is written to standard output, usually the terminal monitor. For example, the SNOBOL4 equivalent of Scheme's

(display "x is equal to ")
(display x)
(newline)

where the value of x is an integer, would be

OUTPUT = "x is equal to " x

(In SNOBOL4, the blank is used as a string-concatenation operator.)

(2) In the C++ programming language, there is a binary operator <<. When the left operand is a text stream (i.e., what Scheme calls an output port connected to text file), the << operator signifies that the value of the right operand is to be output to that stream. The operator is multiply overloaded; for every simple C++ data type, there is a different << procedure to output a value of that type, and the compiler determines which one to use by determining the type of the second operand. (Actually, the << operator is overloaded even further; when an expression of integer type appears as left operand, << signifies a left arithmetic shift, with the number of bit positions to be shifted determined by the value of the second operand.)

In C++, the output statement given as an example above would be written

cout << "x is equal to " << x << "\n";

where cout is the standard output stream and "\n" is a string containing only a line terminator.

(3) For every unstructured data type, and for strings, Modula-2 supplies a special procedure to output a value of that data type: WriteString to output a string, WriteReal to output a real number, and so on, as well as WriteLn to output a line terminator. In Modula-2, the example would be coded as

WriteString ("x is equal to ");
WriteInt (x, 1);
WriteLn

(If you like, you may suggest minor modifications in one of these schemes before announcing your preference for it.)