Sample Exam 2 with Solution - Programming Languages - 2008 | COMP 311, Exams of Programming Languages

Material Type: Exam; Class: PROGRAMMING LANGUAGES; Subject: Computer Science; University: Rice University; Term: Fall 2008;

Typology: Exams

Pre 2010

Uploaded on 08/18/2009

koofers-user-n50
koofers-user-n50 🇺🇸

10 documents

1 / 12

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Comp 311: Sample Exam II
November 24, 2008
Name:
Id #:
Instructions
1. The examination is closed book. The type checking rules for (Implicitly)
Polymorphic Jam are given on the first three pages of the exam as a
reference.
2. Fill in the information above and the pledge below.
3. There are 7 problems on the exam worth a total of 110 points.
4. You have four hours to complete the exam. You must take the exam
during a continuous four hour block plus an optional 10 minute break. Do
not discuss the contents of the exam with anyone other than the instructor
and teaching assistants between now and the due date for the exam.
Pledge:
1
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Sample Exam 2 with Solution - Programming Languages - 2008 | COMP 311 and more Exams Programming Languages in PDF only on Docsity!

Comp 311: Sample Exam II

November 24, 2008

Name:

Id #:

Instructions

  1. The examination is closed book. The type checking rules for (Implicitly) Polymorphic Jam are given on the first three pages of the exam as a reference.
  2. Fill in the information above and the pledge below.
  3. There are 7 problems on the exam worth a total of 110 points.
  4. You have four hours to complete the exam. You must take the exam during a continuous four hour block plus an optional 10 minute break. Do not discuss the contents of the exam with anyone other than the instructor and teaching assistants between now and the due date for the exam.

Pledge:

Synopsis of Implicitly Polymorphic Jam

The syntax of (Implicitly) Polymorphic Jam is a restriction of the syntax of untyped Jam. Every legal Polymorphic Jam program is also a legal untyped Jam Program. But the converse is false, because there may not be a valid typing for a given untyped Jam program.

Abstract Syntax

The following grammar describes the abstract syntax of Polymorphic Jam. Each clause in the grammar corresponds directly to a node in the abstract syntax tree. The let construction has been limited to a single binding for the sake of notational simplicity. It is straightforward to generalize the rule to multiple bindings (with mutual recursion). Note that let is recursive.

M ::= M (M · · · M ) | P (M · · · M ) | if M then M else M | let x := M in M | V V ::= map x · · · x to M | x | n | true | false | null n ::= 1 | 2 |... P ::= cons | first | rest | null? | cons? | + | - | / | * | = | < | <= | <- | + | - | ~ | ref |! x ::= variable names

In the preceding grammar, unary and binary operators are treated exactly like primitive functions. Monomorphic types in the language are defined by τ , below. Polymorphic types are defined by σ. The → corresponds to a function type, whose inputs are to the left of the arrow and whose output is to the right of the arrow.

σ ::= ∀α 1 · · · αn. τ τ ::= int | bool | unit | τ 1 × · · · × τn → τ | α | list τ | ref τ α ::= type variable names

Type Checking Rules

In the following rules, the notation Γ[x 1 : τ 1 ,... , xn : τn] means the Γ ∪ {x 1 : τ 1 ,... , xn : τn}.

Γ true : bool Γ false : bool Γ ` n : int

Γ[x 1 : τ 1 ,... , xn : τn] M : τ Γ map x 1... xn to M : τ 1 × · · · × τn → τ

[abs]

Γ M : τ 1 × · · · × τn → τ Γ M 1 : τ 1 · · · Γ Mn : τn Γ M (M 1 · · · Mn) : τ

[app]

Types of Primitives

The following table gives types for all of the primitive functions and operators and the polymorphic constant null. Programs are type checked starting with a primitive type environment consisting of this table.

null ∀α. list α cons ∀α. α × list α → list α first ∀α. list α → α rest ∀α. list α → list α cons? ∀α. list α → bool null? ∀α. list α → bool = ∀α. α × α → bool

  • int × int → int
  • int × int → int
  • int × int → int / int × int → int

< int × int → bool <= int × int → bool

(unary) - int → int (unary) + int → int (unary) ˜ bool → bool <- ∀α. ref α × α → unit ref ∀α. α → ref α ! ∀α. ref α → α

Typed Jam

The Typed Jam language used in Assignment 5 (absent the explicit type infor- mation embedded in program text) can be formalized as a subset of Polymorphic Jam. For the purposes of this test, Typed Jam is simply Polymorphic Jam less the letpoly inference rule which prevents it from inferring polymorphic types for program-defined functions.

Problem 1. [15 points]

(i) [5 points] Give a simple example of an untyped Jam expression (which is not a value) that is not typable in Polymorphic Jam, yet does not generate a run-time error when executed. Briefly but convincingly explain why.

The program (map x to x(x)) (map x to x(x)), commonly called Omega, is not typable in Polymorphic Jam yet does not generate a run-time error. It is not typable because the body of the function (map x to x(x)) con- tains the self-application x(x) which is not typable. x(x) is not typable because x has a function type α → β with an input type α that equals the function type α → β. But these two type are not unifiable because α → β contains α. Circular bindings of type variables are not allowed in Polymorphic Jam. The program does not generate a run-time error because (map x to x(x)) (map x to x(x)) is not a value but directly (“in one step”) reduces to itself generating a divergent computation.

(ii) [5 points] Give a simple example of an untyped Jam expression that is not typable in Typed Jam, but is typable in Polymorphic Jam. Briefly but convincingly explain why.

The program let id = map x to x; in (id(id))(17) is typable in Poly- morphic Jam but not in Typed Jam because the id function is polymor- phic. It is used with two different typings in the body of the let. Tbe inner occurrence of id has type int → int while the outer occurrence has type (int → int) → (int → int).

(iii) [5 points] Assume that we extend Polymorphic Jam by dropping the “value restriction” on the right hand side of bindings in letpoly rule and add the block construct (definable as an expansion into map application) and the corresponding typing rule. Give a simple example of a program that is typable in extended Polymorphic Jam but generates a run-time type error (misinterpreting one type of data as another) when it is executed.

let fn := ref(map x to x); in { fn <- map x to x+1; (!fn)(true); } The preceding program uses fn polymorphically: once as type ref(int → int)), so the assigment to fn is type correct, and once as type ref(bool → bool, so the application of !fn to true is type correct. But the assign- ment places a function of type int → int in the cell fn, which fails when it is applied to true because !fn tries to add 1 to its argument x. There are no polymorphic values in Polymorphic Jam (or in ML/OCaml for that matter) only amibiguous ones (like null and map x to x) with types that are determined by context.

(ii) [15 points] Is the same program

let foldr := map f,e,l to if null?(l) then e else f(first(l), foldr(f, e, rest(l))); in foldr(cons, null, cons(foldr(map x,y to x+y, 0, cons(1,null)), null))

typable in Polymorphic Jam? Justify your answer in same way as in part (i).

Yes. The detailed proof derivation is elided, but the subproof generating a type for the right-hand-side of the foldr binding generates the type (α × β → β) × β × α − list → β where α and β are fresh type variables (not in Γ for the typing of the entire program). In the subproof assigning a type to the body of the let, foldr has the polymorphic type (a type scheme) ∀α, β[(α × β → β) × β × α − list → β] which enables foldr to have the two distinct typings described in the solution to part (i).

Problem 3. [25 points] Convert the following untyped Jam program to CPS. Use the identity func- tion as your top level continuation and do not CPS either nested lets or applica- tions of primitive operations (primitive functions or operators). Note that let is recursive.

let foldr := map f,e,l to if null?(l) then e else f(first(l), foldr(f, e, rest(l))); in foldr(map x,y to x+y, 0, cons(1,null))

Your CPS translation simply has to put all calls on program defined functions in tail position.

let foldrK := map fK,m,l,k to if null?(l) then k(e) else foldrK(f, e, rest(l), map v to fK(first(l), v, k)); in foldrK(map x,y,k to k(x+y), 0, cons(1,null), map v to v)