General List.foldl algebra shared across the Mathlib-free hex libraries.
The computational libraries repeatedly fold an accumulator with a single
operation, xs.foldl (fun acc x => acc + f x) z or its multiplicative twin.
Lean core already proves the underlying facts — List.foldl_assoc,
List.sum_eq_foldl, List.foldl_map — but those need Std.Associative /
Std.LawfulIdentity instances on the carrier, which a bare
Lean.Grind.Semiring does not carry. This module supplies those four
instances file-locally (just enough to prove the lemmas below) and then
states the fold-algebra the libraries actually use.
The lemmas live in the List namespace and follow the standard-library
naming: name the operation, not the use site (foldl_add_*, foldl_mul_*),
mirror List.foldl_assoc/List.foldl_map, and keep foldl_add_eq_add_foldl
symmetric with foldl_mul_eq_mul_foldl. The one exception is
foldl_const_step: core/Mathlib already use List.foldl_const for the
unrelated iterate lemma, so reusing that name here would collide in the
Mathlib bridge layers (which import both this module and Mathlib). These are
candidates to migrate up to lean4; the Grind Std instances in particular
belong with the Grind algebra hierarchy.
The Std.Associative / Std.LawfulIdentity instances that List.foldl_assoc
and friends need are kept file-local: they are used only to prove the
lemmas below, which state their conclusions over Lean.Grind.Ring / CommRing
without exposing the instances. Keeping them local avoids adding a second
global Std.Associative resolution path for every Grind.Semiring (e.g.
Nat/Int in the Mathlib bridge layers, where Mathlib already supplies its
own). Promote / upstream them separately if a consumer ever needs them.
Addition in a Grind.Semiring is an associative operation.
Multiplication in a Grind.Semiring is an associative operation.
0 is a two-sided identity for addition in a Grind.Semiring.
1 is a two-sided identity for multiplication in a Grind.Semiring.
Congruence #
Pull the running accumulator out of a multiplicative fold-product, taking
the product from a 1 start. Stated for any associative multiplication with a
two-sided unit, so it applies to monoids that are not Grind rings (e.g. the
executable polynomial types).
Constant step #
Folding with a step that discards the element and returns the accumulator
unchanged yields the initial accumulator. (Core's List.foldl_const is the
unrelated iterate lemma, hence the name.)
Permutation invariance #
A multiplicative fold-product is invariant under permuting the list.
Accumulator extraction #
Pull the running accumulator out of an additive fold-sum, taking the sum
from a 0 start. The additive twin of foldl_mul_eq_mul_foldl.
All-zero collapse #
An additive fold-sum whose body adds a literal 0 returns the initial
accumulator.
Scalar factoring #
Factor a right scalar out of an additive fold-sum (right distributivity, no commutativity needed).
Negation and subtraction #
Additivity #
An additive fold-sum of a pointwise sum splits into two folds, distributing the starting accumulator.
An additive fold-sum of a pointwise sum splits into two folds, given a splitting of the starting accumulator.
An additive fold-sum of a pointwise sum from 0 splits into the sum of the
two separate folds from 0.
An additive fold-sum of a pointwise difference splits into the difference of the two fold-sums, distributing the starting accumulator.
An additive fold-sum of a pointwise difference from 0 splits into the
difference of the two fold-sums from 0.
Fubini #
Sum-swap (Fubini) for nested additive fold-sums.
flatMap #
Indicator pickout #
An additive fold-sum over a Nodup list whose summand is supported at a
single matching element collects exactly that summand.