### Written: Typed

### Problem 1

Consider a datatype definition that introduces numeric lists as the
sum of two variants: `nempty`

and `ncons`

. This
defines a new type (`nlist`

), and each constructor (such as
`ncons`

) creates a value of that type. As a result,
however, selectors (such as `nfirst`

) cannot statically
determine whether or not they have been given the correct variant of
the datatype, and must rely on a check from the run-time system.

On the Web, you read a proposal for a better design: Suppose, instead,
each variant creates a new type. Then you can give a precise type for
the selector (e.g., above, `nfirst`

would take only
`ncons`

values, not `nempty`

or
`nlist`

ones), thus turning the dynamic check into a static
one, thereby increasing the effectiveness of the type system. Because
this was proposed in Twitter, it's frustratingly short on details.

Write at most a page (of reasonably-sized text) exploring this design. Can we build an effective type system out of this idea? If so, how, and if not, why not? If we can't as stated, can we turn this into something that actually works? Have you seen any languages that do something like this? Solutions to this problem which are much shorter than one page are certainly acceptable so long as they get the point across.

### Problem 2

Consider the program:

`(+ 1 (first (cons true empty)))`

This program has a type error.

Generate constraints for this program. Isolate the smallest set of these constraints that, solved together, identify the type error.

Feel free to label the sub-expressions above with superscripts for use when writing and solving constraints.

### Problem 3

Consider the following typed expression:

{fun {f : B1 } : B2 {fun {x : B3 } : B4 {fun {y : B5 } : B6 {cons x {f {f y}}}}}}

We have left the types unspecified (`Bn`

) to be filled in by the type inference
process. Derive type constraints from the above program. Then solve these
constraints. From these solutions, fill in the values of the boxes. Be sure to
show all the steps specified by the algorithms (i.e., writing the answer based
on intuition or knowledge is insufficient). You should use type variables where
necessary. To save writing, you can annotate each expression with an
appropriate type variable, and present the rest of the algorithm in terms of
these type variables alone (to avoid having to copy the corresponding
expressions). If you do this, be sure to annotate every sub-expression with a
type variable. Be sure the annotations are clearly readable!

### Problem 4

The textbook notes that recursive types enable us to type ω (and, by extension, Ω). Provide a type for the function ω, and discuss informally how type-checking would work with the type you describe to bless an application of ω to itself.

Reminder: we defined ω as `(lambda (x) (x x))`

, and Ω
as the application of ω to itself: `((lambda (x) (x x)) (lambda (x) (x x))).`

### Problem 5

*
Because we introduced this problem after the original problem set went
out, you are not required to do it. You may do it for bonus points,
or you may do it in place of one of the other three problems.
*

In Java, there is no single type for numbers, and `float`

,
`int`

, etc., are all distinct types and very few of these
can be directly substituted for others. At the other extreme, in
Typed Racket, both `Integer <: Number`

and
`Float <: Number`

, and indeed there is a large and
complex subtype hierarchy of numbers (including types such as
`Nonpositive-Float`

and even `Positive-Byte`

)
that you can look up in its documentation.

What are the tradeoffs between these two designs?

### Handin

Put your solution to each problem in a separate text file labeled {1, 2, 3, 4}.txt. If you do the fifth problem, you may turn in 5.txt and/or leave out one of the first four files.

From the directory containing the files for this assignment, execute

/course/cs173/bin/cs173handin types-writ