ListFold: Verified Left-Fold in OCaml
- ListFold is the canonical left-fold operation on lists in functional programming, defined with formal specifications using the Gospel language.
- Its OCaml implementation employs recursion and ghost invariants, ensuring termination and correctness through permitted and complete predicates.
- Deductive verification via the Gospel→WhyML→Why3 pipeline confirms that ListFold adheres exactly to the canonical equational definition for left-fold.
ListFold is the canonical left-fold operation on lists, fundamental in functional and higher-order programming. In the context of formal verification, especially as articulated by the "Unfolding Iterators" methodology, ListFold is specified, implemented, and deductively verified using OCaml in combination with the Gospel specification language and the Cameleer verification framework. This approach enables modular and rigorous reasoning about higher-order iteration schemas, ensuring that classic iterators such as left-fold are correct with respect to precise logical specifications (Chirica et al., 25 Jun 2025).
1. Specification of ListFold via the Gospel Contract
The specification of ListFold is formalized through Gospel, a behavioral specification language designed for OCaml. The ListFold function assumes the type signature:
3
The Gospel contract uses the folds clause, introducing two key predicates:
- permitted: Enforces that the sequence of visited elements is a prefix of the input list, i.e., for all , and .
- complete: Specifies completeness once all elements have been visited, i.e., .
There is no further requires clause; totality is assumed for all lists. The use of folds instructs the toolchain to synthesize a first-order cursor-loop matching functional recursion over the list structure (Chirica et al., 25 Jun 2025).
2. OCaml Implementation and Invariants
A direct recursive implementation of ListFold adheres to standard functional programming idioms, with explicit Gospel annotations specifying termination and correctness invariants. The implementation is:
4
- The
variant length xsguarantees termination by ensuring each recursive call operates on a shorter list. - The ghost invariant ensures that at every recursion point, the accumulator matches the left-fold of the function over the currently processed prefix of
xs. That is, for every prefix and residual such that , the accumulator satisfies (Chirica et al., 25 Jun 2025).
3. Equational Characterization and Correctness
The correctness theorem for ListFold, as produced by Why3 from the specification and implementation, states that the list_fold function coincides with the standard equational definition of left-fold:
with the inductive unfolding:
For specific 0 and 1 (e.g., 2, 3), this recovers familiar computations such as sums over lists (Chirica et al., 25 Jun 2025).
4. Verification Conditions and Proof Methodology
Deductive verification within Cameleer—via the Gospel→WhyML→Why3 pipeline—produces a finite set of verification conditions (VCs):
- Termination VC: Proves that 4 at each recursive call.
- Precondition VC: Validates the ghost invariant at function entry; trivially satisfied (5, 6).
- Invariant-Preservation VC: Shows the invariant's inductive step holds at each recursive call.
- Postcondition VC: At the base case (7), confirms 8.
Key to discharging these VCs is the existential invariant 9. The proof steps involve pattern-matching inversion, instantiating existential witnesses (0), and utilizing Why3’s list-library lemmas. Proofs for arithmetic and simple list equalities are resolved automatically by the SMT solver Alt-Ergo (Chirica et al., 25 Jun 2025).
5. Modularity and Ghost State Techniques
The methodology hinges on two crucial ideas:
- Ghost state: Tracking the processed prefix of 1 via an existential variable 2 ensures accurate reasoning about functional state across iterations.
- permitted/complete abstraction: These Gospel contract components modularize the iteration schema, describing the expected access pattern over the data structure and when computations are complete.
Once ListFold is verified, correctness results transfer to any client instantiating the fold pattern (e.g., sum, map, filter), as all such instantiations reuse the same loop skeleton and VCs. This modularity is key for deductive verification of higher-order iterators (Chirica et al., 25 Jun 2025).
6. High-Level Proof Strategy and Challenges
The overarching strategy initiates from a high-level Gospel contract, automatically translates it to a WhyML function skeleton (using explicit recursion and ghost state), and generates Why3 VCs corresponding to termination, invariant preservation, and correctness. The loop invariant and permitted/complete predicates enable reduction of the higher-order verification task to standard first-order recursive reasoning.
A primary challenge in verifying higher-order iterators is universal quantification over function arguments. By "unfolding" the iteration into an explicit cursor-based recursion, the verification reduces to proof of classic loop invariants. The infrastructure provided by Cameleer, Gospel, and automated solvers makes such proofs tractable in practice, with little manual intervention given suitable contracts and invariants (Chirica et al., 25 Jun 2025).