course) that "<code>x:α</code>" represents an expression `x`
whose type is <code>α</code>.
-Then System F can be specified as follows (choosing notation that will
-match up with usage in O'Caml, whose type system is based on System F):
+Then System F can be specified as follows:
System F:
---------
simply-typed lambda calculus. So in a lingusitics context, type
constants might include `e` and `t`. "α" is a type variable. The
tick mark just indicates that the variable ranges over types rather
-than over values; in various discussion below and later, type variable
+than over values; in various discussion below and later, type variables
can be distinguished by using letters from the greek alphabet
(α, β, etc.), or by using capital roman letters (X, Y,
etc.). "`τ1 -> τ2`" is the type of a function from expressions of
have at least one free occurrence of `α` somewhere inside of it.
In the definition of the expressions, we have variables "`x`" as usual.
-Abstracts "`λx:τ. e`" are similar to abstracts in the simply-typed lambda
+Abstracts "`λx:τ.e`" are similar to abstracts in the simply-typed lambda
calculus, except that they have their shrug variable annotated with a
type. Applications "`e1 e2`" are just like in the simply-typed lambda calculus.
System F|http://www.cis.upenn.edu/~bcpierce/tapl/index.html]] (the
relevant evaluator is called "fullpoly"):
- N = ∀α. (α->α)->α->α;
- Pair = (N->N->N) -> N;
- let zero = α . λs:α->α . λz:α. z in
- let fst = λx:N . λy:N . x in
- let snd = λx:N . λy:N . y in
- let pair = λx:N . λy:N . λz:N->N->N . z x y in
- let suc = λn:N . λα . λlambda s:α->α . λz:α . s (n [α] s z) in
- let shift = λp:Pair . pair (suc (p fst)) (p fst) in
- let pre = λn:N . n [Pair] shift (pair zero zero) snd in
+ N = ∀α.(α->α)->α->α;
+ Pair = (N->N->N)->N;
+
+ let zero = Λα. λs:α->α. λz:α. z in
+ let fst = λx:N. λy:N. x in
+ let snd = λx:N. λy:N. y in
+ let pair = λx:N. λy:N. λz:N->N->N. z x y in
+ let suc = λn:N. Λα. λs:α->α. λz:α. s (n [α] s z) in
+ let shift = λp:Pair. pair (suc (p fst)) (p fst) in
+ let pre = λn:N. n [Pair] shift (pair zero zero) snd in
pre (suc (suc (suc zero)));
The key to the extra expressive power provided by System F is evident
in the typing imposed by the definition of `pre`. The variable `n` is
-typed as a Church number, i.e., as `∀ α . (α->α)->α->α`. The type
+typed as a Church number, i.e., as `∀α.(α->α)->α->α`. The type
application `n [Pair]` instantiates `n` in a way that allows it to
manipulate ordered pairs: `n [Pair]: (Pair->Pair)->Pair->Pair`. In
other words, the instantiation turns a Church number into a
In fact, unlike in the simply-typed lambda calculus,
it is even possible to give a type for ω in System F.
-<code>ω = lambda x:(∀ α. α->α) . x [∀ α . α->α] x</code>
+<code>ω = λx:(∀α.α->α). x [∀α.α->α] x</code>
In order to see how this works, we'll apply ω to the identity
function.
<code>ω id ==</code>
- (lambda x:(∀ α . α->α) . x [∀ α . α->α] x) (lambda α . lambda x:α . x)
+ (λx:(∀α.α->α). x [∀α.α->α] x) (Λα.λx:α.x)
-Since the type of the identity function is `(∀ α . α->α)`, it's the
+Since the type of the identity function is `∀α.α->α`, it's the
right type to serve as the argument to ω. The definition of
ω instantiates the identity function by binding the type
-variable `α` to the universal type `∀ α . α->α`. Instantiating the
+variable `α` to the universal type `∀α.α->α`. Instantiating the
identity function in this way results in an identity function whose
type is (in some sense, only accidentally) the same as the original
fully polymorphic identity function.
With these basic types, we want to say something like this:
- and:t->t->t = lambda l:t . lambda r:t . l r false
- and = lambda α . lambda β .
- lambda l:α->β . lambda r:α->β .
- lambda x:α . and:β (l x) (r x)
+ and:t->t->t = λl:t. λr:t. l r false
+ and = Λα.Λβ.λl:α->β.λr:α->β.λx:α. and [β] (l x) (r x)
The idea is that the basic *and* conjoins expressions of type `t`, and
when *and* conjoins functional types, it builds a function that