The Iris Tutorial in Lean

5.5. Hoare Triples🔗

Having studied weakest preconditions, we shift our focus onto another construct for specifying program behaviour: Hoare triples. The weakest precondition does not explicitly specify which conditions must hold before executing the program; it only talks about the postcondition. Hoare triples build on weakest preconditions by requiring us to explicitly mention the precondition.

The Rocq syntax is {{{ P }}} e {{{ x .. y, RET v ; Q }}}. It desugars to

□ (∀ Φ, P -∗ ▷ (∀ x .. y, Q -∗ Φ v) -∗ WP e {{ w, Φ w }})

iris-lean does not yet ship the {{{ P }}} e {{{ ... }}} sugar, so in this port we write the desugared wand-rolled form directly. One loss: we don't get the persistence automatically; we either add it by hand or skip it when the spec only needs to be applied once.

Consider a function that swaps two values.

def swap : Val := hl_val(λ x y, let v := !x; x !y; y v)
-- TODO (upstream — iris-lean): port the Hoare-triple notation
-- `{{{ P }}} e {{{ x .. , RET v ; Q }}}`. Until then a Hoare-
-- triple-styled specification must be written out as the
-- desugared wand-rolled WP. (The proof itself uses `wp_pures` +
-- `wp_load`/`wp_store`, all of which work today — only the
-- statement-level sugar is missing.)

-- Rocq tutorial reference:
--   Lemma swap_spec (l1 l2 : loc) (v1 v2 : val) :
--     {{{ l1 ↦ v1 ∗ l2 ↦ v2 }}}
--       swap #l1 #l2
--     {{{ RET #(); l1 ↦ v2 ∗ l2 ↦ v1 }}}.
--   Proof.
--     iIntros "%Φ [H1 H2] HΦ".
--     rewrite /swap.
--     wp_pures. wp_load. wp_load. wp_store. wp_store.
--     iApply "HΦ". by iFrame.
--   Qed.

A convention in Iris is to write specifications using Hoare triples but prove them by converting them to weakest preconditions. This convention applies equally to the iris-lean port; once the notation lands, the chapter's swap_spec and swap_swap_spec will translate without issue, because every primitive law they use is already in Iris.HeapLang.PrimitiveLaws.