Programming Language Design 2

STLC With Integers And Booleans


Learning Objectives

  • You know how to add integers and comparison operators to the simply typed lambda calculus.
  • You understand the evaluation and typing rules related to integers and comparison operators.

Extending STLC with integers and booleans is straightforward.

As a reminder: the previous chapter worked with the language of STLC+𝟚:

Var:StringTermApp:(Term,Term)TermAbs:(String,Type,Term)TermTrue,False:TermIte:(Term,Term,Term)Term

We add the following terms on top:

Num:TermAdd,Mul,Sub:(Term,Term)TermEq,Ne,Lt,Le,Gt,Ge:(Term,Term)Term Definition 6.6.1: Terms and types of STLC++𝟚The set of terms STLC++𝟚, which is referred to as Term during thischapter, is inductively defined using the following data constructors:Var:StringTermApp:(Term,Term)TermAbs:(String,Type,Term)TermTrue,False:TermIte:(Term,Term,Term)TermNum:TermAdd,Mul,Sub:(Term,Term)TermEq,Ne,Lt,Le,Gt,Ge:(Term,Term)Term

Extending Evaluation

To extend evaluation to cover the new terms, we first need to extend is_value and subst.

Extending Values

Definition 6.6.2: Value (STLC++𝟚)In STLC++𝟚 abstractions, true, false and num terms are values.is_value:Term{0,1}is_valueAbs()=1is_valueTrue=1is_valueFalse=1is_valueNum(_)=1is_value_=0

Extending Substitution

We simply add the new terms to make substitution cover all cases. The value Num is invariant under substitution, and recursive constructors are mapped with the substitution.

As there are no new variable binding operators, we don’t need to worry about that.

Definition 6.6.3: Substitution (STLC++𝟚)In STLC++𝟚 substituting a variable name by a term in a term isdefined as follows.subst:(String,Term,Term)Termsubst𝑥 𝑣Var(𝑥)=𝑣subst𝑥 𝑣Var(𝑦)=Var(𝑦),if𝑥𝑦subst𝑥 𝑣App(𝑡1,𝑡2)=App(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Abs(𝑥,𝑇,𝑡)=Abs(𝑥,𝑇,𝑡)subst𝑥 𝑣Abs(𝑦,𝑇,𝑡)=Abs(𝑦,𝑇,subst(𝑥,𝑣,𝑡))if𝑥𝑦subst𝑥 𝑣Let(𝑥,𝑡1,𝑡2)=Let(𝑥,subst(𝑥,𝑣,𝑡1),𝑡2)subst𝑥 𝑣Let(𝑦,𝑡1,𝑡2)=Let(𝑦,subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))if𝑥𝑦subst𝑥 𝑣True=Truesubst𝑥 𝑣False=Falsesubst𝑥 𝑣Ite(𝑡1,𝑡2,𝑡3)=Ite(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2),subst(𝑥,𝑣,𝑡3))subst𝑥 𝑣Num(𝑛)=Num(𝑛)subst𝑥 𝑣Add(𝑡1,𝑡2)=Add(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Mul(𝑡1,𝑡2)=Mul(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Sub(𝑡1,𝑡2)=Sub(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Eq(𝑡1,𝑡2)=Eq(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Ne(𝑡1,𝑡2)=Ne(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Lt(𝑡1,𝑡2)=Lt(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Le(𝑡1,𝑡2)=Le(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Gt(𝑡1,𝑡2)=Gt(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))subst𝑥 𝑣Ge(𝑡1,𝑡2)=Ge(subst(𝑥,𝑣,𝑡1),subst(𝑥,𝑣,𝑡2))In addition, the notation [𝑥𝑣]𝑡 stands for subst"x"𝑣 𝑡.

Evaluation Rules

Now we are ready to add the missing evaluation rules. We need to cover how to evaluate Add,Mul,Sub,Eq,Ne,Lt,Le,Gt,Ge.

𝑡1𝑡1Add1Add(𝑡1,𝑡2)Add(𝑡1,𝑡2)𝑡2𝑡2is_value𝑣1Add2Add(𝑣1,𝑡2)Add(𝑣1,𝑡2)AddAdd(Num(𝑛),Num(𝑚))Num(𝑛+𝑚)

The rules for Mul and Sub are similar and all work in the same mazZer, reducing the left-hand-side with the Add1 rule until it is value, then reduce the right-hand-side with Add2, and finally Add rule does the computation with the integer values.

The rules for comparisons can be written in the following way:

𝑡1𝑡1Lt1Lt(𝑡1,𝑡2)Lt(𝑡1,𝑡2)𝑡2𝑡2is_value𝑣1Lt2Lt(𝑣1,𝑡2)Lt(𝑣1,𝑡2)𝑛<𝑚LtTrueLt(Num(𝑛),Num(𝑚))True¬(𝑛<𝑚)LtFalseLt(Num(𝑛),Num(𝑚))False

Rules for Le,Gt,Ge are similar.

Next, the rules for equality should only compare types which can be compared for equality, i.e. integers and booleans, and not e.g. functions.

𝑡1𝑡1Eq1Eq(𝑡1,𝑡2)Eq(𝑡1,𝑡2)𝑡2𝑡2is_value𝑣1Eq2Eq(𝑣1,𝑡2)Eq(𝑣1,𝑡2)𝑛=𝑚EqNumTrueEq(Num(𝑛),Num(𝑚))True𝑛𝑚EqNumFalseEq(Num(𝑛),Num(𝑚))False

The rules for comparing booleans and Ne are left out for brevity.

Extending Type Checking

The STLC base language only had rules for type checking variables, abstractions and applications:

VarΓ,𝑥::𝑇𝑥::𝑇Γ,𝑥::𝑇1𝑡1::𝑇2AbsΓ𝜆𝑥:𝑇1. 𝑡1::𝑇1𝑇2Γ𝑡1::𝑇1𝑇2Γ𝑡2::𝑇1AppΓ𝑡1 𝑡2::𝑇2

The ternary relation is highlighted as follows:

  • blue is used to highlight the context,
  • no highlighting is used for the term and
  • red is used to highlight the type.

These rules don’t need to be changed, only new rules need to be added for the new terms.

Type checking integers and booleans works just the same as in part 4 chapter 7, but with the added context.

FalseΓFalse::BooleanTrueΓTrue::BooleanΓ𝑡𝑐::BooleanΓ𝑡2::𝑇Γ𝑡1::𝑇IteΓIte(if:𝑡𝑐,then:𝑡1,else:𝑡2)::𝑇NumΓNum(𝑛)::IntegerΓ𝑡1::IntegerΓ𝑡2::IntegerAddΓAdd(𝑡1,𝑡2)::IntegerΓ𝑡1::IntegerΓ𝑡2::IntegerMulΓMul(𝑡1,𝑡2)::IntegerΓ𝑡1::IntegerΓ𝑡2::IntegerSubΓSub(𝑡1,𝑡2)::Integer

We also need to type check Eq,Ne,Lt,Le,Gt,Ge:

Γ𝑡1::IntegerΓ𝑡2::IntegerEqΓEq(𝑡1,𝑡2)::BooleanΓ𝑡1::IntegerΓ𝑡2::IntegerNeΓNe(𝑡1,𝑡2)::Boolean

The rules for Lt,Le,Gt,Ge are similar.

Loading Exercise...