~/bend-docscommunity

list.bend checks

raw source on the hub · import 0x085d89db9ee8a21865e959816bb20e5b/list.bend as MList

List.append, List.reverse and List.length — the lemmas Base does not ship.

Base ships a rich term library for List and not one fact about it: nothing says append is associative, that reverse.go meets append, or that length is additive. These six are the facts every proof over List ends up writing by hand. Same shape, same proof idiom and same rewrite rule as the String package (0x89df026edd2acf2673b5e469e037eaf1/string.bend):

%lem(args) : P P is the goal AFTER the rewrite, with _ at the position the lemma's LEFT side was put in; the right side is the form being eliminated. So a lemma is written {target == what-the-goal-holds-now}.

append_nil2 {a == append(a, [])} eliminates append(a, []) append_assoc2 {append(a, append(b,c)) == append(append(a,b), c)} reverse_go_spec {append(reverse(a), acc) == reverse.go(a, acc)} reverse_append2 {append(reverse(b), reverse(a)) == reverse(append(a, b))} reverse_reverse {a == reverse(reverse(a))} eliminates reverse(reverse(a)) length_append {length(a) + length(b) == length(append(a, b))}

The rewrite rule decides each statement's orientation, so the statements are the ones a proof wants to rewrite *towards*: the left side is the shape the goal should end up in.

Every parameter is used exactly once, except acc in reverse_go_spec and ys in reverse_append2: those two proofs rewrite twice through the same value, so the checker needs them marked + (reusable) -- the same mark string.bend puts on its acc. Every cons is matched as Con{+h, +t} for the same reason: the proofs mention the head in the goal and again in a step, and the tail in two steps.

1 import
import Base

Definitions

def append_nil2 source · line 35 · raw

@xs:List<&2, Nat> -> {xs == List.append(&2, Nat, xs, []) : List<&2, Nat>}

def append_assoc2 source · line 43 · raw

@xs:List<&2, Nat> -> @ys:List<&2, Nat> -> @zs:List<&2, Nat> -> {List.append(&2, Nat, xs, List.append(&2, Nat, ys, zs)) == List.append(&2, Nat, List.append(&2, Nat, xs, ys), zs) : List<&2, Nat>}

def reverse_go_spec source · line 52 · raw

@xs:List<&2, Nat> -> @+acc:List<&2, Nat> -> {List.append(&2, Nat, List.reverse(&2, Nat, xs), acc) == List.reverse.go(&2, Nat, xs, acc) : List<&2, Nat>}

def reverse_append2 source · line 63 · raw

@xs:List<&2, Nat> -> @+ys:List<&2, Nat> -> {List.append(&2, Nat, List.reverse(&2, Nat, ys), List.reverse(&2, Nat, xs)) == List.reverse(&2, Nat, List.append(&2, Nat, xs, ys)) : List<&2, Nat>}

def reverse_reverse source · line 76 · raw

@xs:List<&2, Nat> -> {xs == List.reverse(&2, Nat, List.reverse(&2, Nat, xs)) : List<&2, Nat>}

def length_append source · line 86 · raw

@xs:List<&2, Nat> -> @ys:List<&2, Nat> -> {Nat.add(List.length(&2, Nat, xs), List.length(&2, Nat, ys)) == List.length(&2, Nat, List.append(&2, Nat, xs, ys)) : Nat}