4.3. Pure Constructs
open Iris.HeapLang
namespace HeapLangExamples
HeapLang has native support for integers and booleans. With these,
we can do basic arithmetic and control flow. Note that values in
HeapLang are prefixed by a #.
def arith : Exp := hl(#1 + #2 * #3)
The expected result of evaluating arith is 7.
def booleans : Exp := hl((#1 + #2 * #3 = #7) && #true || (#true = #false))
The expected result is #true.
-- TODO (upstream — iris-lean): use the unit literal here once the
-- `hl` DSL gains a sugared form for `Val.lit BaseLit.unit` (Rocq: `#()`).
def if_then_else : Exp := hl(if #true then #1 else #0)
In the Rocq version of this example, the consequent is the unit
value #(); iris-lean does not yet have a sugared spelling for the
unit literal, so we use an integer here instead.
HeapLang supports let expressions. Technically, let expressions are
not native to HeapLang — they are sugar for application of a lambda
to its argument. Note that variables in HeapLang are strings; in
the Lean DSL, you write them as plain identifiers, and they elaborate
to Exp.var "x".
def lets : Exp := hl(
let a := #4;
let b := #2;
a + b)
HeapLang has native support for pairs, with tuples being notation for nested pairs.
def pairs : Exp := hl(
let p := (#40, #1 + #1);
fst(p) + snd(p))
def tuples : Exp := hl(
let t1 := (#1, #2, #3, #4);
let t2 := (((#1, #2), #3), #4);
snd(fst(fst(t1))) = snd(fst(fst(t2))))
We can also do pattern matching using sums. A common use case of sums is the option construction.
def sums : Exp := hl(
let r := injr(#1);
match r with
| injl(_) => #0
| injr(n) => n + #1
)
def option : Exp := hl(
let r := some(#1);
match r with
| none() => #0
| some(n) => n + #1
)
Finally, we have lambda abstractions and recursive functions. As with let expressions, lambda abstractions are also a derived construct — they are recursive functions that do not recurse. In HeapLang, functions are first-class citizens, which gives support for higher-order functions.
def lambda : Exp :=
hl(let add5 := (λ x, x + #5);
let double := (λ x, x * #2);
let compose := (λ f g, λ x, g (f x));
compose add5 double #5)
def recursion : Exp :=
hl(let fac := (rec f n := if n = #0 then #1 else n * f (n - #1));
(fac #4, fac #5))