lean4-htt/tests/lean/run/unfoldr.lean
Leonardo de Moura 9ba41a692d
feat: unfold [reducible] class fields (part 1) (#12340)
This PR implements better support for unfolding class fields marked as
`reducible`. For example, we want to mark fields that are types such as
```lean
MonadControlT.stM : Type u -> Type u
```
The motivation is similar to our heuristic that type definitions should
be abbreviations.
Now, suppose we want to unfold `stM m (ExceptT ε m) α` using the
`.reducible` transparency setting, we want the result to be `stM m m
(MonadControl.stM m (ExceptT ε m) α)` instead of
`(instMonadControlTOfMonadControl m m (ExceptT ε m)).1 α`. The latter
would defeat the intent of marking the field as reducible, since the
instance `instMonadControlTOfMonadControl` is `[instance_reducible]` and
the resulting term would be stuck when using `.reducible` transparency
mode.

**Remark**: This feature introduces a few breakages in core and Mathlib.
So, it is disabled for now in this PR. To enable, we must use
`set_option backward.whnf.reducibleClassField true`
2026-02-06 16:18:33 +00:00

48 lines
1.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

notation "#(" a ")" => ⟨a, by decreasing_tactic⟩
def List.unfoldr {α β : Type u} [sz : SizeOf β] (f : (b : β) → Option (α × { b' : β // sizeOf b' < sizeOf b})) (b : β) : List α :=
match f b with
| none => []
| some (a, ⟨b', h⟩) => a :: unfoldr f b'
def tst1 (n : Nat) : List Nat :=
List.unfoldr (b := n) fun
| 0 => none
| b+1 => some (3*n - b*2, #(b))
#guard tst1 10 == [12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
def tst2 (n : Nat) : List Nat :=
-- Similar example where we provide our custom `SizeOf` instance
List.unfoldr (sz := ⟨fun b => n - b⟩) (b := 0) fun b =>
if h : b < n then
some (b*2, ⟨b+1, by simp [sizeOf]; omega⟩)
else
none
#guard tst2 10 == [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
-- More general (and less convenient to use) version that can take an arbitrary well-founded relation.
def List.unfoldr' {α β : Type u} [w : WellFoundedRelation β] (f : (b : β) → Option (α × { b' : β // w.rel b' b})) (b : β) : List α :=
match f b with
| none => []
| some (a, ⟨b', h⟩) => a :: unfoldr' f b'
termination_by b
-- We need the `master` branch to test the following example
def tst3 (n : Nat) : List Nat :=
List.unfoldr' (b := n) fun
| 0 => none
| b+1 => some (3*n - b*2, #(b))
#guard tst3 10 == [12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
def tst4 (n : Nat) : List Nat :=
List.unfoldr' (w := invImage (fun b => n - b) inferInstance) (b := 0) fun b =>
if h : b < n then
some (2*b, #(b+1))
else
none
#guard tst4 10 == [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]