Type Systems: Understanding the Role of Types in Functional Programming, Study notes of Programming Languages

An introduction to type systems, their origins in mathematics, and their implementation in functional programming languages, specifically the l-calculus. It covers the concept of types, typing rules, and natural deduction systems. The document also discusses the relationship between untyped and simply typed l-calculus, the type reconstruction algorithm, and robin milner's creative leaps in extending the simply typed l-calculus with polymorphism.

Typology: Study notes

Pre 2010

Uploaded on 08/16/2009

koofers-user-4hp
koofers-user-4hp 🇺🇸

9 documents

1 / 12

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
COMP 311 1
Type Systems
COMP 311
Rice University
Houston, Texas
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Type Systems: Understanding the Role of Types in Functional Programming and more Study notes Programming Languages in PDF only on Docsity!

COMP 311

Rice University

Houston, Texas

Type Systems for Programming Language were invented by

mathematicians before electronic computers were invented.

What is a type? A meaningful subset of the set of the domain of data

values used in a program. Types are used to describe the intended

behavior of program operations.

The concept is derived from mathematics; functions have specified domain

and co-domains sets which are often called types. In fact, a function with

domain A and co-domain B is often said to have type A Æ B. Moveover,

the variables used in mathematical formulas typically have specified types

Mathematicians informally check that uses of functions and variables in

formulas are respected just as they informally check that reasoning used in

proofs is sound.

In computer programs, some forms of “type checking” can be formalized

and automated.

Typing rules for the (simply) typed l-calculus

  • Each constant c Œ C has a given type c( c )
  • Since an expression M inside a l-calculus program may contain free

variables, type rules keep track of the types of these variables using a type

environment G Õ V ¥ T where T denotes the set of types t. This type

environment is simply a symbol table that records a symbol’s type!

  • Assume M :s Æ t and N : s. Then (M N): t.
  • Assume x : s implies that M : t. Then (l x : s M ): s Æ t

The process of assigning types to l-calculus programs can be rigorously

formalized as a natural deduction system where the formal sentences are

typing judgements of the form G |- M : t and the mechanisms for generating

true sentences are

  • axioms of the form G |- M : t and
  • inference rules of the form

G 1 |- M 1 : t 1 , …, GN |- M N: tN fi G |- M : t

Explanation:

  • Axioms are typing judgements that are manifestly true.
  • Inference rules produce true consequences given true premises
  • Common notation for rules

G 1 |- M 1 : t 1 , …, GN |- M N:tN

G |- M : t

Natural deduction rules for (simply typed l-calculus) [G is arbitrary]

  • G, x :t |- x : t
  • G |- c : c( c )
  • G |- M :s Æ t, G |- N :s (Æ elimination or application)

G |- (M N): t.

  • G, x :s |- M : t. (Æ introduction or abstraction)

G |- (l x :s M ): s Æ t

Type Systems : Sample Typing Proof

Show:

∅ | (l f : int Æ int. (l g : int Æ int. (l x : int. ( f ( g x ))))): ( int Æ int) Æ (( int Æ int) Æ ( int Æ int ))

Tree1: f : int Æ int, g : int Æ int, x : int | g : int Æ int , f : int Æ int, g : int Æ int, x : int | x : int

f : int Æ int, g : int Æ int, x : int | ( g x ): int

Tree2: f : int Æ int, g : int Æ int, x : int | f : int Æ int , Tree

f : int Æ int, g : int Æ int, x : int | ( f ( g x )): int

f : int Æ int, g : int Æ int | (l x : int. ( f ( g x ))): int Æ int

f : int Æ int | ((l g : int Æ int. (l x : int. ( f ( g x )))) : ( int Æ int) Æ (int Æ int)

∅ | (l f : int Æ int. (l g : int Æ int. (l x : int. ( f ( g x ))))) : ( int Æ int) Æ (( int Æ int) Æ (int Æ int))

COMP 311 8

Question: what is the relationship between the (untyped) l-calculus and the (simply)

typed l-calculus?

_ Many expressions (and complete programs) in the (untyped) l-calculus cannot

be typed in the (simply) typed l-calculus!

_ Example: (l x ( x x))

x requires a type s = s Æ t, but no such type exists

_ If the constant operations terminate for all inputs, then every typable program

terminates for all inputs!

Question: is there a tractable algorithm for determining the type of an expression in the (untyped) l-calculus and rejecting the expression if no such type exists? Yes! The standard algorithm (called the type reconstruction algorithm) is based on a very simple idea:

_ generate a distinct type variable for every subexpression of the given expression M,

_ record the equality constraints between these variables dictated by the typing rule that matches the program context in which the subexpression associated with each variable appears, and

_ solve these constraints.

What is unification? Tree pattern matching where match variables only appear as leaves. _ A naïve recursive algorithm can be written in a few lines of Scheme or ML. _ The common practical algorithm relies on a union-find representation of finite sets to record equivalent symbolic types. Every set contains at least one symbolic type that is just a variable. This algorithm runs in essentially linear time. _ A linear algorithm exists but it is not as efficient for problems of practical size as the union-find based algorithm.

_ Question: is the reconstructed type unique? Many l - calculus programs have multiple typings. Consider the program (l x x). It can be assigned the type sÆs, for any type s Œ T , e.g., (int Æ int), (i n t Æ int) Æ (i n t Æ int), …

The type reconstruction algorithm deftly addresses this problem by returning the most general symbolic typing; all of the possible ground typings (containing no type variables) are substitution instances of this typing. For this reason, the typing produced by the type reconstruction algorithm is called the principal typing (or type) of the program.

Robin Milner’s Creative Leaps

_ The simple type system for the l - calculus is truly onerous because

polymorphic functions (those with variables in their principal types) have to be rewritten for each different typing. The original Pascal language suffers from precisely this problem.

Milner recognized that a surprisingly useful form of polymorphism could be added to the (simply) typed l - calculus by adding a let construct to the language family. The extension adds one new form to the family syntax M ::= … | (let ( x M) M) Given an expression of the form (let ( x M) N) x can be used polymorphically in N without breaking the principal typing property. Type reconstruction can first infer the principal type of M and subsequently use a renamed version of this type (a fresh name for each distinct type variable) for each distinct occurrence of x in N.