A Ruby implementation of the type checker described in Chapter 10 of Benjamin C. Pierce's "Types and Programming Languages" mobbed during a meeting of London Computation Club on Tuesday, 23rd May 2017.
git clone git://github.com/computationclub/simple-types.git
cd simple-types
bundle install
make
This syntax makes use of a few non-ASCII symbols for operators. All have ASCII alternatives should you be working in an environment where typing these symbols is a faff. They are:
λ
, used to begin an abstraction, alternative:\
⇒
, to introduce case clause bodies, alternative:=>
→
, the function type operator, alternative:->
×
, the product type operator, alternative:*
Syntax | Node |
---|---|
x |
Term::Var(name: string) |
λx:T. t |
Term::Abs(param: string, type: type, body: term) |
t t |
Term::Application(left: term, right: term) |
T → T |
Type::Function(from: type, to: type) |
Syntax | Node |
---|---|
true |
Term::True |
false |
Term::False |
if t then t else t |
Term::If(condition: term, consequent: term, alternate: term) |
Bool |
Type::Boolean |
Syntax | Node |
---|---|
0 |
Term::Zero |
succ t |
Term::Succ(arg: term) |
pred t |
Term::Pred(arg: term) |
iszero t |
Term::Iszero(arg: term) |
Nat |
Type::Natural |
Syntax | Node |
---|---|
T |
Type::Base(name: string) |
Syntax | Node |
---|---|
unit |
Term::Unit |
Unit |
Type::Unit |
Syntax | Node |
---|---|
t ; t |
Term::Sequence(first: term, last: term) |
Syntax | Node |
---|---|
t as T |
Term::Ascribe(term: term, type: type) |
Syntax | Node |
---|---|
let x=t in t |
Term::Let(param: string, arg: term, body: term) |
Syntax | Node |
---|---|
t.1 , t.foo |
Term::Project(object: term, field: int | string) |
Syntax | Node |
---|---|
{t | t} |
Term::Pair(left: term, right: term) |
T × T |
Type::Product(left: type, right: type) |
Syntax | Node |
---|---|
{t, t, ...} |
Term::Tuple(members: [term]) |
{T, T, ...} |
Type::Tuple(members: [type]) |
Syntax | Node |
---|---|
{foo=t, bar=t, ...} |
Term::Record(members: {string => term}) |
{foo: T, bar: T, ...} |
Type::Record(members: {string => type}) |
In these terms, clause
means Term::CaseClause(param: string, body: term)
Syntax | Node |
---|---|
inl t |
Term::Inl(term: term) |
inr t |
Term::Inr(term: term) |
inl t as T |
Term::Inl(term: term, type: type) |
inr t as T |
Term::Inr(term: term, type: type) |
case t of inl x ⇒ t | inr x ⇒ t |
Term::SumCase(term: term, left: clause, right: clause) |
T + T |
Type::Sum(left: type, right: type) |
In these terms, clause
means Term::CaseClause(param: string, body: term)
Syntax | Node |
---|---|
<label=t> as T |
Term::Tagged(label: string, term: term, type: type) |
case t of <foo=x> ⇒ t | <bar=x> ⇒ t | ... |
Term::VarCase(term: term, clauses: {string => clause}) |
<foo: T, bar: T, ...> |
Type::Variant(clauses: {string => type}) |
Syntax | Node |
---|---|
nil[T] |
Term::Nil(type: type) |
cons[T] t t |
Term::Cons(type: type, head: term, tail: term) |
isnil[T] t |
Term::Isnil(type: type, arg: term) |
head[T] t |
Term::Head(type: type, arg: term) |
tail[T] t |
Term::Tail(type: type, arg: term) |
List T |
Type::List(type: type) |
Syntax | Node |
---|---|
ref t |
Term::Ref(value: term) |
!t |
Term::Deref(ref: term) |
t := t |
Term::Assign(ref: term, value: term) |
Ref T |
Type::Ref(type: type) |