Additional exercises

Course links

A.1. Find a diagram illustrating proposition 2 of book VII of Euclid's Elements, either in a published edition of that work or on line. Make a hard copy. On your copy, label each line segment mentioned in the text of Euclid's proof with a natural number giving its length, in such a way that the account given in the proof accurately describes the arithmetic operations and results.

A.2. Using mathematical induction, prove the correctness of Euclid's algorithm -- either Euclid's version of it, or the Scheme definition shown at the end of the handout. Which is easier?

A.3. Describe the Algol 60 compound statement (see page 5 of the handout on Backus-Naur form) in unextended BNF.

A.4. The basic form of Java for-statement is the one shown in the example on page 6 of the handout on Backus-Naur form. Recent versions of Java also support an "enhanced" form of the for-statement, with the concrete syntax

<for-stmt> ::= for ( <type> <identifier> : <expr> ) <stmt>

Revise the data type definition for for-stmt so that it supports both basic and enhanced forms (as variants).

A.5. The variable-declaration part of a Pascal program, procedure definition, or function definition consists of the keyword var followed by one or more declarations, each consisting of one or more identifiers (separated by commas), a colon, and either an identifier or a constructed type. Each declaration is terminated by a semicolon.

Translate this description into one or more BNF rules. (You can assume that the category <constructed-type> is defined elsewhere.) Then write a data type definition for it.

A.6. A grammar for the Lua programming language, expressed in extended BNF, can be found at the end of the Lua 5.1 reference manual). Construct data type definitions for the syntactic categories defined there.

Note that the manual's authors use square brackets to enclose optional components and curly braces to enclose components that can be repeated any number of times. So the extended BNF rule that they write as

funcname ::= Name {`.' Name} [`:' Name]

would, if written using the BNF conventions adopted in the handout, appear as

<funcname> ::= <name> {. <name>}* {: <name>}?

A.7. The ARITHMETIC language is implemented in six Scheme files: expval.scm, tokens.scm, and syntax-trees.scm, which define the shared data types for expressed and denoted values, lexical tokens, and abstract syntax trees, respectively; and scanner.scm, parser.scm, and interpreter.scm, which respectively carry out the lexical analysis, parsing proper, and evaluation of programs in the language.

For each of the following proposed changes or improvements in the ARITHMETIC language, describe the changes, if any, that one would have to make in each of the six Scheme files in order to implement it. Then choose one of the proposed changes, implement it, and test the resulting code.

A.8. The concrete syntax that ARITHMETIC uses for subtraction doesn't match the usual mathematical conventions, in which subtraction is an infix operator:

<expression> ::= <expression> - <expression>

But using this concrete syntax in ARITHMETIC would have complicated the parser and forced other troublesome modifications in the syntax. Explain why. (Hint: Construct an example, using the infix syntax, in which the minuend is an if-expression.)

A.9. Add a new kind of expression to ARITHMETIC, one that includes two subexpressions, each having a number as value. When evaluated, an expression of this new kind should determine whether its subexpressions have equal values, returning (bool-val #t) if they do and (bool-val #f) if not. Choose a concrete syntax that harmonizes with the existing syntax. Implement and test your design.

A.10. In the PROC program presented in exercise 3.23 of the textbook (page 81), examine each occurrence of an identifier and state whether it is a declaration or a reference. In addition, state the lexical address of each reference.

A.11. Use the λ-calculus axioms and rules of inference to prove that (^n.^f.^x.(f ((n f) x)) ^g.^y.(g (g y))) = ^f.^x.(f (f (f x))) (or, in other words, that the successor of two is three!).

A.12. By hand, evaluate the λ-calculus expression (((^x.^y.^z.((z ^w.y) x) u) v) ^x.^y.y) by performing as many successive beta-reductions on it as possible. You may choose any evaluation order.

A.13. In an abnormal-order evaluator for the λ-calculus, we choose always to reduce the rightmost maximal beta-redex in the current expression, and we keep reducing until no more beta-redexes remain. Implement an abnormal-order evaluator for LAMBDA. Give an example of a LAMBDA expression that has a normal form, but runs forever in the abnormal-order evaluator.

A.14. Give an example of a LAMBDA expression that terminates with a normal form in a normal-order evaluator, terminates but does not yield a normal form in an applicative-order evaluator without partial evaluation, and does not terminate in an applicative-order evaluator with partial evaluation.

A.15. Modify the implementation of the run procedure in the normal-form evaluator for LAMBDA so that it not only returns the normal form of each expression that it is given, but also displays, as a side effect, the number of beta-reductions that the evaluator performed in reaching that normal form.

A.16. An arithmetic predicate in the λ-calculus is a function that returns either true or false when given any Church numeral (in other words, the application of the function to the Church numeral is always beta-reducible to true or to false).

Define and test a function minarg that takes any arithmetic predicate f and returns the Church numeral for the least natural number n that satisfies f (that is, the least one for which the application is beta-reducible to true). It is all right, and indeed desirable, for there to be no normal form when minarg is applied to an arithmetic predicate that returns false for every Church numeral.

A.17. In the λ-calculus, define and test a ``binary'' function equal? that tests whether two given Church numerals represent the same number. In other words, ((equal? m) n) should be beta-reducible to true when the same Church numeral is substituted for both m and n, but to false when different Church numerals are dropped in.

A.18. In the λ-calculus, define and test a ``binary'' function append that constructs and returns the result of concatenating two given lists.

A.19. Write an expression in EXPLICIT-REFS that has, as its value, a (curried) procedure that takes two references as arguments, exchanges the values stored in those references, and returns the true Boolean value.

A.20. How many values can the Icon expression not (0 to 5) generate, and what are those values? Why do Griswold and Griswold describe not as a "control structure" (p. 23) rather than an operator?

A.21. Complete the following Icon program so that it prints out all the Pythagorean triples (a, b, c) of positive integers less than or equal to 25 -- the triples such that a2 + b2 = c2.

procedure main()
  every (YOUR EXPRESSION HERE) do
    write("(", a, ", ", b, ", ", c, ")")
end

A.22. Add a not-expression to the GENERATORS language, with the syntax

not <expression>

When evaluated, a not-expression should fail if its subexpression succeeds and should succeed (once), producing the value 0, if its subexpression fails.

A.23. Read chapters 7 and 8 of The Icon programming language, then write (1) an Icon procedure that takes one argument, an integer greater than or equal to 2, and succeeds if that integer is prime but fails if it is not; (2) an expression that generates all the "twin primes," i.e., pairs of prime numbers differing by 2; and (3) a program that prints out the first hundred twin-prime pairs. Use two-element lists to represent pairs.

A.24. Read chapter 7 of The Icon programming language, then add to GENERATORS (1) a list data type, as in exercise 3.9 of Friedman and Wand, and (2) a unary element operator, with the syntax

element ( <expression> )

that generates the elements of a given list. (For instance, the expression every print(element(ls)) do fail should print out the elements of ls.)

A.25. Read chapter 7 of The Icon programming language, then add to GENERATORS (1) a repeated-alternation operator like the one Griswold and Griswold describe on pages 94 and 95, with the syntax

regenerate <expression>

and (2) a limited-generation operator like the one that Griswold and Griswold describe on pages 93 and 94, with the syntax

stopafter <expression> for <expression>

where the first expression, which must have a numeric value, imposes the maximum number of values that can be recovered from the second expression's result sequence. Note that the order in which the subexpression appear in a stopafter-expression is the opposite of the order in which they appear in Icon's limited-generation expressions.

Two other notes:

(1) A repeated-alternation expression fails immediately if its subexpression fails immediately.

(2) Do not allow control backtracking from the second subexpression of a stopafter-expression into the first one.

A.26. Add to the "academic ancestry" example (/home/stone/courses/languages/examples/academicFamilyTrees.pro) one or more rules for a Prolog relation cousin that holds between to individuals if they have a common academic ancestor but did not have the same advisor.