Sum and product types

Product types

Read TAPL 11.6-8.

Pierce shows how to add pairs, tuples (which are an easy generalization of pairs), and records (which are basically tuples with named members).

Scheme cons cells, Python tuple, and C struct are real-world examples of product types.

The i ∈ 1..n notation that the book uses is a bit hard to read; here’s a less rigorous notation that also uses evaluation contexts.

t ::= ...
      {t, t, ...}
      t.i             (i≥1)

v ::= ...
      {v, v, ...}

T ::= ...
      {T, T, ...}

E ::= ...
      E.i
      {v, v, ..., E, t, t, ...}

{v1, v2, ...}.j  vj             E-ProjTuple

  Γ ⊢ t1 : T1  Γ ⊢ t2 : T2  ...
―――――――――――――――――――――――――――――――――  T-Tuple
Γ ⊢ {t1, t2, ...} : {T1, T2, ...}

Γ ⊢ t : {T1, T2, ...}
―――――――――――――――――――――              T-Proj
     Γ ⊢ t.j : Tj

Sum types

Read TAPL 11.9-10.

Pierce presents two kinds of sum types: sums and variants, which are an easy generalization of sums.

C union is not quite the same as a sum type, because a C union variable doesn’t “know” which of the two unioned types it belongs to. Sum types are often called tagged unions to distinguish from C-style untagged unions.

Question: Why don’t untyped languages (Scheme, Python) typically have sum types?

In order to preserve uniqueness of types, TAPL adds as clauses in many places. For variants, these are actually not necessary if we require that every label uniquely determines a variant type. This is, in fact, the case in many languages, like ML and Haskell (p. 141). We will adopt this convention.

Again, the notation gets a bit hard to read; here’s a less rigorous version.

t ::= ...
      <l=t>
      case t of <l=x>  t, <l=x>  t, ...

T ::= ...
      <l:T, l:T, ...>

E ::= ...
      case E of <l=x>  t, <l=x>  t, ...
      <l=E>

case <lj=vj> of <l1=x1>  t1, <l2=x2>  t2, ...  [xjvj]tj      E-CaseVariant

           Γ ⊢ tj:Tj
―――――――――――――――――――――――――――――――                                       T-Variant
Γ ⊢ <lj=tj>:<l1:T1, l2:T2, ...>

Γ ⊢ t:<l1:T1, l2:T2, ...>   Γ, x1:T1 ⊢ t1:T   Γ, x2:T2 ⊢ t2:T   ...
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――   T-Case
        Γ ⊢ case t of <l1=x1>  t1, <l2=x2>  t2 : T

Assuming that we have a Unit type, we can define variants like

Color ≡ <red:Unit, green:Unit, blue:Unit>

which are analogous to C/C++/Java enum. In particular, we no longer need Bool to be built in; we can define it ourselves:

Bool ≡ <false:Unit, true:Unit>

Exercise. Show how to simulate if if Bool is defined as above.

Propositions as types (graduate only)

Now would be a good time to bring up the Curry-Howard isomorphism (pages 108-109). Forget about type systems for a moment and think about propositional logic.

We define a syntax of formulas:

φ ::= x
      true
      false
      φ  φ
      φ ∧ φ
      φ ∨ φ

And inference rules for Γ ⊢ φ (“under the assumptions in Γ, φ is provable”):

――――――――
Γ ⊢ true

――――――――
Γ, φ ⊢ φ

 Γ, φ1 ⊢ φ2
――――――――――――                              (→ introduction)
Γ ⊢ φ1  φ2                              
                                          
Γ ⊢ φ1  φ2  Γ ⊢ φ1                      
――――――――――――――――――――                      (→ elimination, or modus ponens)
       Γ ⊢ φ2                             
                                          
Γ ⊢ φ1  Γ ⊢ φ2                            
――――――――――――――                            (∧ introduction)
 Γ ⊢ φ1 ∧ φ2                              
                                          
Γ ⊢ φ1 ∧ φ2                               
―――――――――――   i ∈ {1,2}                   (∧ elimination)
  Γ ⊢ φi                                  
                                          
   Γ ⊢ φi                                 
―――――――――――   i ∈ {1,2}                   (∨ introduction)
Γ ⊢ φ1 ∨ φ2

Γ ⊢ φ1 ∨ φ2   Γ ⊢ φ1  φ   Γ ⊢ φ1  φ
―――――――――――――――――――――――――――――――――――――――   (∨ elimination)
                Γ ⊢ φ

This is a restriction of propositional logic called intuitionistic propositional logic that doesn’t have negation.

The Curry-Howard isomorphism is a correspondence between proof systems in logic and type systems in programming language theory. Notice the similarity between these rules and the typing rules we’ve built up so far.

proof systems type systems
formulas φ types T
assumptions Γ contexts Γ
Γ ⊢ φ Γ ⊢ t:T for some t
×
+
true unit

This naturally leads to a number of questions, like:

  • What does false correspond to? The empty type, usually written .
  • What do and correspond to?
  • What does negation correspond to?