Skip to content

Commit 5a2faa0

Browse files
committed
feat: InfoTree API: InfoTree.findSome(M)? and InfoTree.onHighestNode? (#31725)
This PR adds the following basic `InfoTree` API: ```lean def findSome? {α} (f : ContextInfo → Info → PersistentArray InfoTree → Option α) (t : InfoTree) (ctx? : Option ContextInfo := none) : Option α ``` ```lean def findSomeM? {m : Type → Type} [Monad m] {α} (f : ContextInfo → Info → PersistentArray InfoTree → m (Option α)) (t : InfoTree) (ctx? : Option ContextInfo := none) : m (Option α) ``` ```lean def onHighestNode? {α} (t : InfoTree) (ctx? : Option ContextInfo) (f : ContextInfo → Info → PersistentArray InfoTree → α) : Option α ``` Note that `onHighestNode?` has an explicit `Option ContextInfo` argument. This is because `onHighestNode?` is more likely to be called in the middle of a larger traversal, during which it is essential to pass the surrounding `ContextInfo`. Making this argument explicit mitigates the increased risk of a footgun here. This functionality is motivated by use in other PRs. Co-authored-by: thorimur <thomasmurrills@gmail.com>
1 parent 82d756e commit 5a2faa0

File tree

1 file changed

+55
-2
lines changed

1 file changed

+55
-2
lines changed

Mathlib/Lean/Elab/InfoTree.lean

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/-
22
Copyright (c) 2025 Marc Huisinga. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Marc Huisinga
4+
Authors: Marc Huisinga, Thomas R. Murrills
55
-/
66
module
77

@@ -42,4 +42,57 @@ where
4242
| return
4343
modify (·.push tti.suggestion)
4444

45-
end Lean.Elab
45+
namespace InfoTree
46+
47+
/--
48+
Finds the first result of `← f ctx info children` which is `some a`, descending the
49+
tree from the top. Merges and updates contexts as it descends the tree.
50+
51+
`f` is **only** evaluated on nodes when some context is present. An initial context should be
52+
provided via the `ctx?` argument if invoking `findSomeM?` during a larger traversal of the
53+
infotree. A failure to provide `ctx? := some ctx` when `t` is not the outermost `InfoTree` is thus
54+
likely to cause `findSomeM?` to always return `none`.
55+
-/
56+
partial def findSomeM? {m : TypeType} [Monad m] {α}
57+
(f : ContextInfo → Info → PersistentArray InfoTree → m (Option α))
58+
(t : InfoTree) (ctx? : Option ContextInfo := none) : m (Option α) :=
59+
go ctx? t
60+
where
61+
/-- Accumulates contexts and visits nodes if `ctx?` is not `none`. -/
62+
go ctx?
63+
| context ctx t => go (ctx.mergeIntoOuter? ctx?) t
64+
| node i ts => do
65+
let a ← match ctx? with
66+
| none => pure none
67+
| some ctx => f ctx i ts
68+
match a with
69+
| some a => pure a
70+
| none => ts.findSomeM? (go <| i.updateContext? ctx?)
71+
| hole _ => pure none
72+
73+
/--
74+
Finds the first result of `f ctx info children` which is `some a`, descending the
75+
tree from the top. Merges and updates contexts as it descends the tree.
76+
77+
`f` is **only** evaluated on nodes when some context is present. An initial context should be
78+
provided via the `ctx?` argument if invoking `findSome?` during a larger traversal of the infotree.
79+
A failure to provide `ctx? := some ctx` when `t` is not the outermost `InfoTree` is thus likely to
80+
cause `findSome?` to always return `none`.
81+
-/
82+
def findSome? {α} (f : ContextInfo → Info → PersistentArray InfoTree → Option α)
83+
(t : InfoTree) (ctx? : Option ContextInfo := none) : Option α :=
84+
Id.run <| t.findSomeM? f ctx?
85+
86+
/--
87+
Returns the value of `f ctx info children` on the outermost `.node info children` which has
88+
context, having merged and updated contexts appropriately.
89+
90+
If `ctx?` is `some ctx`, `ctx` is used as an initial context. A `ctx?` of `none` should **only** be
91+
used when operating on the first node of the entire infotree. Otherwise, it is likely that no
92+
context will be found.
93+
-/
94+
def onHighestNode? {α} (t : InfoTree) (ctx? : Option ContextInfo)
95+
(f : ContextInfo → Info → PersistentArray InfoTree → α) : Option α :=
96+
t.findSome? (ctx? := ctx?) fun ctx i ch => some (f ctx i ch)
97+
98+
end Lean.Elab.InfoTree

0 commit comments

Comments
 (0)