# Lecture 16 — 2015-11-02

## Recursive types; midterm debriefing

This lecture is written in literate Haskell; you can download the raw source.

Sum types

We first covered sum types, which are the “math” version of Haskell’s `Either` datatype.

``````t ::= ... | t1 + t2
e ::= ... | left e | right e | case e of left x -> e1 | right y -> e2

G |- e : t1
---------------------
G |- left e : t1 + t2

G |- e : t2
---------------------
G |- right e : t1 + t2

G |- e : t1 + t2
G,x:t1 |- e1 : t1
G,y:t2 |- e2 : t2
-------------------------
G |- case e of        : t
left x -> e1
right y -> e2``````

The above rules are “extrinsic” typing rules, since `left` and `right` end up guessing their arguments. We could write subscripted versions (using `_`), like below, to come up with intrinsic forms:

``````t ::= ... | t1 + t2
e ::= ... | left_t2 e | right_t1 e | ...

G |- e : t1
---------------------
G |- left_t2 e : t1 + t2

G |- e : t2
---------------------
G |- right_t1 e : t1 + t2
``````

Note how the left and right constructors are annotated with the type of the other side: `left_t2` says what type the programmer thinks the right side should have.

What values have type `t1 + t2`? Constructors make values; we’ll say that a constructor applied to a value is a value.

``````v ::= ... | left v | right v

---------------------------- CaseLeft
case left v of   --> e1[v/x]
left x -> e1
right y -> e2

---------------------------- CaseLeft
case right v of   --> e2[v/y]
left x -> e1
right y -> e2``````

We can also give big-step rules, using environments:

``````e, env VV left v    e1,env[v/x] VV v'
------------------------------------- CaseLeft
case e of       , env VV v'
left x -> e1
right y -> e2

e, env VV left v    e2,env[v/y] VV v'
------------------------------------- CaseRight
case e of       , env VV v'
left x -> e1
right y -> e2``````

Recursive types

Recursion in Haskell functions and Haskell datatypes uses names. Recursion in the pure lambda calculus uses the Y combinator to write “closed-form” recursive functions. We use μ types to write closed-form recursive datatypes.

Note that `fold_{mu alpha. t}` is meant to be interpreted as a subscript.

``````t ::= ... | mu alpha. t | alpha
e ::= ... | fold_{mu alpha. t} e | unfold e

G |- e : t[mu alpha. t/a]
---------------------------------------
G |- fold_{mu alpha. t} e : mu alpha. t

G |- e : mu alpha. t
--------------------------------
G |- unfold e : t[mu alpha. t/a]``````

These definitions are hard to understand at first blush. Let’s look at the definition for integer lists in Haskell and work our way down:

``````data IntList =
Nil
| Cons Int IntList``````

An `IntList` is either:

• `Nil`, or
• `Cons n l`, such that `n` is an `Int` and `l` is an `IntList`.

In algebraic types, we interpret ‘either’ using sums (written + in math and `Either` in Haskell). So in pseudo-Haskell, we have:

``IntList = Nil + Cons Int IntList``

Next, we don’t use constructor names in algebraic datatypes—we just represent the data. So `Nil` and `Cons` need to be replaced. Now, `Nil` has no arguments—the only information `Nil` provides is that it isn’t `Cons`. We can represent it using `()`, the unit type.

``IntList = () + Cons Int IntList``

`Cons`, on the other hand, has some arguments. We’ll represent them as a pair, using * (or × on paper, or `(,)` in Haskell).

``IntList = () + (Int,IntList)``

At this point, the only left to do is to get rid of the recursion. To do this, we use μ. The process is mechanical: if you have a definition of the form `X = [some type t in terms of X]`, you translate it to `X` = μ α. t[α/X]. Here, that gives us:

``X = mu alpha. () + (Int,alpha)``

Okay: what values have μ types?

``````v ::= ... | fold_{mu alpha. t} v

-----------------------------------
unfold (fold_{mu alpha. t} v) --> v``````

We can also give rules in a big-step style:

``````e, env VV fold_{mu alpha. t} v
------------------------------
unfold e, env VV v``````

Hmm… still not helping. How do we build a value with folds? Let’s use the IntList above to build some lists.

``````IntList = mu alpha. () + (Int,alpha)

nil :: IntList
nil = fold_IntList (left ())``````

Okay… what about a list with elements? I’ll just write `fold` without its subscript, to keep things brief.

``[1,2,3] = fold (right (1,fold (right (2,fold (right (3,fold (left ())))))))``

Okay… how do we define `cons`?

``````cons :: Int -> IntList -> IntList
cons = \x. \xs. fold (right (x,xs))``````

What about `head` and `tail`?

``````head :: IntList -> Int
head xs =
case unfold xs of
left x -> diverge
right y -> fst y

tail :: IntList -> IntList
tail xs =
case unfold xs of
left x -> diverge
right y -> snd y``````

What about `map`?

``````map :: (Int -> Int) -> IntList -> IntList
map f xs =
case unfold xs of
left e -> nil
right c -> cons (f (head c)) (map f (tail c))``````

Midterms

Midterms were handed back at the end of class. If you don’t have yours, I’ll bring it by on Wednesday.

Please check my arithmetic and data entry on Sakai!