Formal Software Verification

6.4. Structures and Records🔗

A structure is an inductive type with a single constructor and named fields, and Lean derives a projection for each field. It is the natural shape for a record of related values. The anonymous constructor ⟨…⟩, the field syntax { … }, and the update syntax { r with … } all build or modify a structure, and extends builds a larger structure on a smaller one. The And.intro of Lecture 1 and the pair of Lecture 3 are themselves single-constructor structures.

namespace Func structure Segment where lo : hi : def width (s : Segment) : := s.hi - s.lo structure NamedSegment extends Segment where name : String end Func

A NamedSegment carries the two fields of Segment and one more, and a projection reaches the inherited fields directly.

6.4.1. Examples🔗

The examples below build, project, update, and extend records.

Example 1. A projection reads a field, and width computes from two of them.

namespace Func def seg1 : Segment := { lo := 1, hi := 5 } example : width seg1 = 4 := width seg1 = 4 All goals completed! 🐙 end Func

Example 2. The field syntax { … } and the anonymous constructor ⟨…⟩ build the same value.

namespace Func def seg2 : Segment := 1, 5 example : seg1 = seg2 := rfl end Func

Example 3. The update syntax { r with … } copies a record and changes one field.

namespace Func def widen (s : Segment) : Segment := { s with hi := s.hi + 1 } example : (widen seg1).hi = 6 := (widen seg1).hi = 6 All goals completed! 🐙 end Func

Example 4. extends adds a field, and the inherited fields stay accessible.

namespace Func def ns1 : NamedSegment := { lo := 0, hi := 2, name := "a" } example : ns1.lo = 0 := ns1.lo = 0 All goals completed! 🐙 end Func

Example 5. The new field is reached like any other.

namespace Func example : ns1.name = "a" := rfl end Func

Example 6. A field may itself be a function, and the projection recovers it.

namespace Func structure Handler where run : def dbl : Handler := { run := fun n => n + n } example : dbl.run 3 = 6 := rfl end Func

Example 7. Building a record and projecting a field returns the field, by computation.

namespace Func example : (1, 5 : Segment).lo = 1 := rfl end Func

Example 8. A function of a record computed from its fields.

namespace Func def midpoint (s : Segment) : := (s.lo + s.hi) / 2 example : midpoint 0, 4 = 2 := midpoint { lo := 0, hi := 4 } = 2 All goals completed! 🐙 end Func

Example 9. Prod is the canonical two-field structure, with Prod.fst and Prod.snd its projections.

example : (Prod.fst (3, 5) : ) = 3 := rfl

Example 10. The And.intro of Lecture 1 is a two-field structure, and the anonymous constructor builds it.

example (a b : Prop) (ha : a) (hb : b) : a b := ha, hb