1-- Heads, tails, constructor laws, the equation lemmas of mapping,2-- reversal, and support that the remaining list modules rewrite with, and3-- the image of a set of lists under a fixed cons4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.List.Basic10import Append11import Reverse1213-- A Boolean choice between two sets; list recursions branch through it.14def boolChoice (test : Bool, yes no : Set) →Set15| Bool.false, yes, no => no16| Bool.true, yes, no => yes1718theorem boolChoice.false (yes no : Set)19shows boolChoice(Bool.false, yes, no) = no20proof21simp [boolChoice]2223theorem boolChoice.true (yes no : Set)24shows boolChoice(Bool.true, yes, no) = yes25proof26simp [boolChoice]2728-- Constructor laws.29theorem List.cons_ne_nil (A a : Set) (xs : List(A))30requires element : a ∈ A31shows a :: xs ≠ []32proof33intro equal34 symm at equal35have distinct := List.inductive.disjoint.nil.cons at a, xs36exact distinct with equal3738theorem List.nil_ne_cons (A a : Set) (xs : List(A))39requires element : a ∈ A40shows [] ≠ a :: xs41proof42exact List.inductive.disjoint.nil.cons at a, xs4344theorem List.cons_injective (A a b : Set) (xs ys : List(A))45requires element : a ∈ A46requires other : b ∈ A47requires equal : a :: xs = b :: ys48shows a = b ∧ xs = ys49proof50exact List.inductive.injective.cons with equal5152theorem List.cons_head (A a b : Set) (xs ys : List(A))53requires element : a ∈ A54requires other : b ∈ A55requires equal : a :: xs = b :: ys56shows a = b57proof58have both := List.cons_injective with equal59exact both.left6061theorem List.cons_tail (A a b : Set) (xs ys : List(A))62requires element : a ∈ A63requires other : b ∈ A64requires equal : a :: xs = b :: ys65shows xs = ys66proof67have both := List.cons_injective with equal68exact both.right6970theorem List.closed_cons (A a : Set) (xs : List(A))71requires element : a ∈ A72shows List(A, a :: xs)73proof74typecheck7576-- Length.77theorem length.eq_zero (A : Set) (xs : List(A))78requires zero : length{A}(xs) =079shows xs = []80proof81have shape := List.cases with*82cases shape with empty | nonempty83 . exact empty84 . obtain⟨a, element, tail, tailList, equal⟩:= nonempty85rw [equal, length.cons] at zero86have distinct := Naturals.disjoint.zero.succ at length{A}(tail)87exfalso88 symm at zero89exact distinct with zero9091theorem length.nil_iff (A : Set) (xs : List(A))92shows length{A}(xs) =0↔ xs = []93proof94constructor95 . intro zero96exact length.eq_zero with zero97 . intro empty98rw empty99exact length.nil at A100101theorem length.cons_positive (A a : Set) (xs : List(A))102requires element : a ∈ A103shows0 < length{A}(a :: xs)104proof105rw length.cons106arith107108theorem length.positive_of_ne_nil (A : Set) (xs : List(A))109requires nonempty : xs ≠ []110shows0 < length{A}(xs)111proof112have shape := List.cases with*113cases shape with empty | cons114 . exfalso115exact nonempty with empty116 . obtain⟨a, element, tail, tailList, equal⟩:= cons117rw equal118exact length.cons_positive with element119120theorem List.ne_nil_of_length_positive (A : Set) (xs : List(A))121requires positive : 0 < length{A}(xs)122shows xs ≠ []123proof124intro empty125rw [empty, length.nil] at positive126exact Less.irreflexive with Naturals.constructor.zero, positive127128theorem length.positive_iff (A : Set) (xs : List(A))129shows0 < length{A}(xs) ↔ xs ≠ []130proof131constructor132 . intro positive133exact List.ne_nil_of_length_positive with positive134 . intro nonempty135exact length.positive_of_ne_nil with nonempty136137theorem length.singleton (A a : Set)138requires element : a ∈ A139shows length{A}(a :: []) =1140proof141simp [length]142143-- Heads and tails.144theorem listTail.nil (A : Set)145shows listTail{A}([]) = []146proof147simp [listTail]148149theorem listTail.cons (A a : Set) (xs : List(A))150requires element : a ∈ A151shows listTail{A}(a :: xs) = xs152proof153simp [listTail]154155theorem listHeadOr.nil (A z : Set)156shows listHeadOr{A}(z, []) = z157proof158simp [listHeadOr]159160theorem listHeadOr.cons (A z a : Set) (xs : List(A))161requires element : a ∈ A162shows listHeadOr{A}(z, a :: xs) = a163proof164simp [listHeadOr]165166theorem listHeadOr.mem_carrier (A z : Set) (xs : List(A))167requires default : z ∈ A168shows listHeadOr{A}(z, xs) ∈ A169proof170have shape := List.cases with*171cases shape with empty | cons172 . rw [empty, listHeadOr.nil]173exact default174 . obtain⟨a, element, tail, tailList, equal⟩:= cons175rw [equal, listHeadOr.cons]176exact element177178theorem listHeadOr.mem_support (A z : Set) (xs : List(A))179requires nonempty : xs ≠ []180shows listHeadOr{A}(z, xs) ∈ listSupport{A}(xs)181proof182have shape := List.cases with*183cases shape with empty | cons184 . exfalso185exact nonempty with empty186 . obtain⟨a, element, tail, tailList, equal⟩:= cons187rw [equal, listHeadOr.cons, listSupport.cons]188exact insert.self189190theorem List.head_tail (A z : Set) (xs : List(A))191requires nonempty : xs ≠ []192shows xs = listHeadOr{A}(z, xs) :: listTail{A}(xs)193proof194have shape := List.cases with*195cases shape with empty | cons196 . exfalso197exact nonempty with empty198 . obtain⟨a, element, tail, tailList, equal⟩:= cons199rw [equal, listHeadOr.cons, listTail.cons]200rfl201202theorem listTail.length (A : Set) (xs : List(A))203requires nonempty : xs ≠ []204shows succ(length{A}(listTail{A}(xs))) = length{A}(xs)205proof206have shape := List.cases with*207cases shape with empty | cons208 . exfalso209exact nonempty with empty210 . obtain⟨a, element, tail, tailList, equal⟩:= cons211rw [equal, listTail.cons, length.cons]212rfl213214theorem listTail.support_subset (A : Set) (xs : List(A))215shows listSupport{A}(listTail{A}(xs)) ⊆ listSupport{A}(xs)216proof217have shape := List.cases with*218cases shape with empty | cons219 . rw [empty, listTail.nil]220exact Subset.reflexive at listSupport{A}([])221 . obtain⟨a, element, tail, tailList, equal⟩:= cons222rw [equal, listTail.cons, listSupport.cons]223intros y hy224exact insert.contains with hy225226-- Append.227theorem append.closed (A : Set) (xs ys : List(A))228shows List(A, append(ys, xs))229proof230typecheck231232theorem append.nil (A : Set) (ys : List(A))233shows append(ys, []) = ys234proof235simp [append]236237theorem append.cons (A a : Set) (xs ys : List(A))238requires element : a ∈ A239shows append(ys, a :: xs) = a :: append(ys, xs)240proof241simp [append]242243theorem append.singleton (A a : Set) (ys : List(A))244requires element : a ∈ A245shows append(ys, a :: []) = a :: ys246proof247simp [append]248249theorem append.eq_nil (A : Set) (xs ys : List(A))250requires empty : append(ys, xs) = []251shows xs = [] ∧ ys = []252proof253have lengths : length{A}(append(ys, xs)) =0254rw empty255exact length.nil at A256rw length.append at lengths257have both := add.eq_zero with lengths258obtain⟨xsZero, ysZero⟩:= both259constructor260 . exact length.eq_zero with xsZero261 . exact length.eq_zero with ysZero262263theorem append.nil_iff (A : Set) (xs ys : List(A))264shows append(ys, xs) = [] ↔ xs = [] ∧ ys = []265proof266constructor267 . intro empty268exact append.eq_nil with empty269 . intro both270obtain⟨xsNil, ysNil⟩:= both271rw [xsNil, ysNil]272simp [append]273274theorem append.length_left_le (A : Set) (xs ys : List(A))275shows length{A}(xs) ≤ length{A}(append(ys, xs))276proof277rw length.append278arith279280theorem append.length_right_le (A : Set) (xs ys : List(A))281shows length{A}(ys) ≤ length{A}(append(ys, xs))282proof283rw length.append284arith285286theorem append.left_nil_of_eq (A : Set) (xs ys : List(A))287requires equal : append(ys, xs) = xs288shows ys = []289proof290have lengths : length{A}(append(ys, xs)) = length{A}(xs)291rw equal292rfl293rw length.append at lengths294have padded : length{A}(xs) + length{A}(ys) = length{A}(xs) +0295rw add.right_unit296exact lengths297have zero := add.left_cancel with padded298exact length.eq_zero with zero299300theorem append.right_nil_of_eq (A : Set) (xs ys : List(A))301requires equal : append(ys, xs) = ys302shows xs = []303proof304have lengths : length{A}(append(ys, xs)) = length{A}(ys)305rw equal306rfl307rw length.append at lengths308have padded : length{A}(xs) + length{A}(ys) =0+ length{A}(ys)309rw add.left_unit310exact lengths311have zero := add.right_cancel with padded312exact length.eq_zero with zero313314-- Support.315theorem listSupport.mem_cons_self (A a : Set) (xs : List(A))316requires element : a ∈ A317shows a ∈ listSupport{A}(a :: xs)318proof319rw listSupport.cons320exact insert.self321322theorem listSupport.mem_cons_of_mem (A a y : Set) (xs : List(A))323requires element : a ∈ A324requires member : y ∈ listSupport{A}(xs)325shows y ∈ listSupport{A}(a :: xs)326proof327rw listSupport.cons328exact insert.contains with member329330theorem listSupport.mem_cons_iff (A a y : Set) (xs : List(A))331requires element : a ∈ A332shows y ∈ listSupport{A}(a :: xs) ↔ y = a ∨ y ∈ listSupport{A}(xs)333proof334rw listSupport.cons335exact insert.membership at y, a, listSupport{A}(xs)336337theorem listSupport.mem_append_iff (A y : Set) (xs ys : List(A))338shows y ∈ listSupport{A}(append(ys, xs)) ↔339 y ∈ listSupport{A}(xs) ∨ y ∈ listSupport{A}(ys)340proof341rw listSupport.append342exact union2.membership at y, listSupport{A}(xs), listSupport{A}(ys)343344theorem listSupport.mem_append_left (A y : Set) (xs ys : List(A))345requires member : y ∈ listSupport{A}(xs)346shows y ∈ listSupport{A}(append(ys, xs))347proof348rw listSupport.append349simp350351theorem listSupport.mem_append_right (A y : Set) (xs ys : List(A))352requires member : y ∈ listSupport{A}(ys)353shows y ∈ listSupport{A}(append(ys, xs))354proof355rw listSupport.append356simp357358theorem listSupport.singleton (A a : Set)359requires element : a ∈ A360shows listSupport{A}(a :: []) = {a}361proof362simp [listSupport]363ext y364simp365366theorem listSupport.eq_empty (A : Set) (xs : List(A))367requires empty : listSupport{A}(xs) =∅368shows xs = []369proof370have shape := List.cases with*371cases shape with nil | cons372 . exact nil373 . obtain⟨a, element, tail, tailList, equal⟩:= cons374have member : a ∈ listSupport{A}(xs)375rw equal376exact listSupport.mem_cons_self with element377rw empty at member378exfalso379exactset.empty with member380381theorem listSupport.empty_iff (A : Set) (xs : List(A))382shows listSupport{A}(xs) =∅↔ xs = []383proof384constructor385 . intro empty386exact listSupport.eq_empty with empty387 . intro nil388rw nil389exact listSupport.nil at A390391theorem listSupport.nonempty_of_ne_nil (A : Set) (xs : List(A))392requires nonempty : xs ≠ []393shows∃ y, y ∈ listSupport{A}(xs)394proof395have shape := List.cases with*396cases shape with nil | cons397 . exfalso398exact nonempty with nil399 . obtain⟨a, element, tail, tailList, equal⟩:= cons400witness a401rw equal402exact listSupport.mem_cons_self with element403404-- Reversal.405theorem reverse.nil (A : Set)406shows reverse{A}([]) = []407proof408simp [reverse]409410theorem reverse.cons (A a : Set) (xs : List(A))411requires element : a ∈ A412shows reverse(a :: xs) = append(a :: [], reverse(xs))413proof414simp [reverse]415416theorem reverse.closed (A : Set) (xs : List(A))417shows List(A, reverse(xs))418proof419typecheck420421theorem reverse.snoc (A a : Set) (xs : List(A))422requires element : a ∈ A423shows reverse(append(a :: [], xs)) = a :: reverse(xs)424proof425have single : List(A, a :: []) bytypecheck426have reversed : List(A, reverse(xs)) bytypecheck427rw [reverse.append, reverse.singleton, append.singleton]428rfl429430theorem reverse.injective (A : Set) (xs ys : List(A))431requires equal : reverse(xs) = reverse(ys)432shows xs = ys433proof434have doubled : reverse(reverse(xs)) = reverse(reverse(ys))435rw equal436rfl437rw [reverse.involutive, reverse.involutive] at doubled438exact doubled439440theorem reverse.eq_nil (A : Set) (xs : List(A))441requires empty : reverse(xs) = []442shows xs = []443proof444have nilReversed : reverse{A}([]) = [] bysimp [reverse]445rw← nilReversed at empty446exact reverse.injective with empty447448theorem reverse.nil_iff (A : Set) (xs : List(A))449shows reverse(xs) = [] ↔ xs = []450proof451constructor452 . intro empty453exact reverse.eq_nil with empty454 . intro nil455rw nil456simp [reverse]457458-- Every nonempty list ends with an element: the mirror image of List.cases.459theorem List.snoc_cases (A : Set) (xs : List(A))460shows xs = [] ∨∃ a ∈ A, ∃ front, List(A, front) ∧ xs = append(a :: [], front)461proof462have reversed : List(A, reverse(xs)) bytypecheck463have shape := List.cases with reversed464cases shape with nil | cons465 . left466exact reverse.eq_nil with nil467 . right468obtain⟨a, element, tail, tailList, equal⟩:= cons469refine⟨a, element, reverse(tail), ?_, ?_⟩470 . typecheck471 . have back : reverse(reverse(xs)) = reverse(a :: tail)472rw equal473rfl474have single : List(A, a :: []) bytypecheck475rw [reverse.involutive, reverse.cons] at back476rw back477rfl478479-- Mapping.480theorem listMap.nil (A f : Set)481shows listMap{A}(f, []) = []482proof483simp [listMap]484485theorem listMap.cons (A f a : Set) (xs : List(A))486requires element : a ∈ A487shows listMap{A}(f, a :: xs) = f(a) :: listMap{A}(f, xs)488proof489simp [listMap]490491theorem listMap.singleton (A f a : Set)492requires element : a ∈ A493shows listMap{A}(f, a :: []) = f(a) :: []494proof495simp [listMap]496497theorem listMap.reverse (A B f : Set) (xs : List(A))498requires function : f : A → B499shows listMap{A}(f, reverse(xs)) = reverse{B}(listMap{A}(f, xs))500proof501induction xs502| List.nil =>503rw [reverse.nil, listMap.nil, reverse.nil]504rfl505| List.cons(a, tail) using ih =>506have element : a ∈ A byassumption507have image := FunctionBetween.apply_closed with function, element508have single : List(A, a :: []) bytypecheck509have reversed : List(A, reverse(tail)) bytypecheck510have mapped : List(B, listMap{A}(f, tail)) byexact listMap.closed with function511have step := listMap.append at A, B, f, reverse(tail), a :: [] with function512rw [reverse.cons, step, ih, listMap.singleton, listMap.cons, reverse.cons]513rfl514515theorem listMap.identity (A : Set) (xs : List(A))516shows listMap{A}(identity(A), xs) = xs517proof518induction xs519| List.nil =>simp [listMap]520| List.cons(a, tail) using ih =>521have element : a ∈ A byassumption522have value := identity.apply with element523rw [listMap.cons, ih, value]524rfl525526theorem listMap.congr (A f g : Set) (xs : List(A))527requires agreement : ∀ x ∈ listSupport{A}(xs), f(x) = g(x)528shows listMap{A}(f, xs) = listMap{A}(g, xs)529proof530induction xs531| List.nil =>532intro agreement533simp [listMap]534| List.cons(a, tail) using ih =>535intro agreement536have element : a ∈ A byassumption537have headIn := listSupport.mem_cons_self with element538have head := agreement with a, headIn539have rest : ∀ x ∈ listSupport{A}(tail), f(x) = g(x)540intros x hx541have member := listSupport.mem_cons_of_mem with element, hx542exact agreement with x, member543have tails := ih with rest544rw [listMap.cons, listMap.cons, head, tails]545rfl546547theorem listMap.eq_nil (A f : Set) (xs : List(A))548requires empty : listMap{A}(f, xs) = []549shows xs = []550proof551have shape := List.cases with*552cases shape with nil | cons553 . exact nil554 . obtain⟨a, element, tail, tailList, equal⟩:= cons555rw [equal, listMap.cons] at empty556have distinct := List.inductive.disjoint.nil.cons at f(a), listMap{A}(f, tail)557exfalso558 symm at empty559exact distinct with empty560561theorem listMap.mem_support (A B f x : Set) (xs : List(A))562requires function : f : A → B563requires member : x ∈ listSupport{A}(xs)564shows f(x) ∈ listSupport{B}(listMap{A}(f, xs))565proof566induction xs567| List.nil =>568intro member569rw listSupport.nil at member570exfalso571exactset.empty with member572| List.cons(a, tail) using ih =>573intro member574have element : a ∈ A byassumption575have image := FunctionBetween.apply_closed with function, element576have mapped : List(B, listMap{A}(f, tail)) byexact listMap.closed with function577have alternatives := listSupport.mem_cons_iff.forward with element, member578rw [listMap.cons, listSupport.cons]579cases alternatives with head | rest580 . rw head581exact insert.self582 . have inner := ih with rest583exact insert.contains with inner584585theorem listMap.support_subset (A B f : Set) (xs : List(A))586requires function : f : A → B587shows listSupport{B}(listMap{A}(f, xs)) ⊆ functionImage(f, listSupport{A}(xs), B)588proof589induction xs590| List.nil =>591rw [listMap.nil, listSupport.nil]592exact empty.subset593| List.cons(a, tail) using ih =>594have element : a ∈ A byassumption595have image := FunctionBetween.apply_closed with function, element596have mapped : List(B, listMap{A}(f, tail)) byexact listMap.closed with function597rw [listMap.cons, listSupport.cons]598intros y hy599have alternatives := insert.membership.forward with hy600cases alternatives with head | rest601 . rw head602have headIn := listSupport.mem_cons_self with element603exact functionImage.membership.backward with⟨image, a, headIn, rfl⟩604 . have inner := ih with y, rest605obtain⟨yIn, x, hx, equal⟩:= functionImage.membership.forward with inner606have member := listSupport.mem_cons_of_mem with element, hx607exact functionImage.membership.backward with⟨yIn, x, member, equal⟩608609theorem listMap.support (A B f : Set) (xs : List(A))610requires function : f : A → B611shows listSupport{B}(listMap{A}(f, xs)) = functionImage(f, listSupport{A}(xs), B)612proof613have forward := listMap.support_subset with function614apply Subset.antisymmetric with forward615intros y hy616obtain⟨yIn, x, hx, equal⟩:= functionImage.membership.forward with hy617rw equal618exact listMap.mem_support with function, hx619620-- The head and tail of a list over A.621theorem List.cons_parts (A x xs : Set)622requires list : List(A, x :: xs)623shows x ∈ A ∧ List(A, xs)624proof625have shape := List.cases at A, x :: xs with list626cases shape with isNil | isCons627 . exfalso628have distinct := List.inductive.disjoint.nil.cons at x, xs629 symm at isNil630exact distinct with isNil631 . obtain⟨y, hy, tail, tailList, equal⟩:= isCons632obtain⟨headEqual, tailEqual⟩:=633 List.inductive.injective.cons with equal634rw [headEqual, tailEqual]635exact⟨hy, tailList⟩636637-- The lists of a set S with a fixed entry prepended.638def consImage (x S : Set) : Set:= { x :: ys | ys ∈ S }639