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:String→TermApp:(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:Stringβ†’TermApp:(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...