Zulip Chat Archive
Stream: lean4
Topic: Lexicographic order on `SubExpr.Pos`
Eric Wieser (Jul 17 2024 at 00:08):
Does the order which sorts SubExpr.Pos
from left to right exist? It would allow lookup in an RBMap
for "match or ancestor", using docs#RBMap.lowerBound and something like
/-- Determine if `a` is an ancestor of `b`. -/
partial def Lean.SubExpr.Pos.isAncestorOf (a b : SubExpr.Pos) : Bool :=
if (a.push 0).asNat ≤ b.asNat then
a.isAncestorOf b.tail
else
a.asNat == b.asNat
Kyle Miller (Jul 17 2024 at 17:32):
If this is for doing computations on positions that come from the delaborator, something to watch out for is that some positions are non-hierarchical, coming from docs#Lean.PrettyPrinter.Delaborator.SubExpr.nextExtraPos. These are characterized by the fact that in base-4 they start with 2 or 3, unlike the hierarchical positions, which start with 1.
For hierarchical positions, I think using lex order on the result of docs#Lean.SubExpr.Pos.toArray gives what you want.
An algorithm that would involve less memory allocation would be to take positions a
and b
(represented as Nat
), find m
and n
such that the log-base-4 of a*4^m
and b*4^n
have the same integer part (one of m
or n
can be zero), and then use the usual Nat order.
Kyle Miller (Jul 17 2024 at 17:37):
Maybe this?
def log4 (n : Nat) : Nat :=
let rec go (n : Nat) (acc : Nat) : Nat :=
if n < 4 then
acc
else
go (n / 4) (acc + 1)
go n 0
def Lean.SubExpr.Pos.compare (a b : Pos) : Ordering :=
let m := log4 a.asNat
let n := log4 b.asNat
Ord.compare (a.asNat * 4^(n-m)) (b.asNat * 4^(m-n))
Eric Wieser (Jul 17 2024 at 17:55):
log4
is docs#Lean.SubExpr.Pos.depth, right?
Kyle Miller (Jul 17 2024 at 17:58):
Yes, looks like it
Eric Wieser (Jul 17 2024 at 17:58):
Is the non-heirarchical representation documented anywhere?
Kyle Miller (Jul 17 2024 at 17:58):
(Side note: it's pretty amazing that the termination checker works for definitions like log4 now)
Eric Wieser (Jul 17 2024 at 17:59):
(I guess foldr
could be made non-partial
then?)
Kyle Miller (Jul 17 2024 at 17:59):
Eric Wieser said:
Is the non-heirarchical representation documented anywhere?
Only barely, near nextExtraPos
, but it doesn't say what they're for.
Eric Wieser (Jul 17 2024 at 18:00):
The context of this question was working out how to expand the positions in the return value of docs#Lean.Widget.exprDiff to correspond to the actual subexpressions that exist in the tagged text
Eric Wieser (Jul 17 2024 at 18:01):
Since right now, the diff can compute a diff in a position which isn't hoverable in the infoview, and so no diff appears
Kyle Miller (Jul 17 2024 at 18:01):
I think something to keep in mind is that SubExpr.Pos is not meant to be an index into the expression
Kyle Miller (Jul 17 2024 at 18:01):
It's simply a scheme to get unique identifiers without needing to keep track of global state
Kyle Miller (Jul 17 2024 at 18:02):
Delaborators are allowed to synthesize new subexpr positions as needed, so long as it's done in a way that won't collide with others
Kyle Miller (Jul 17 2024 at 18:03):
The linkage of a Pos to an expr is in the collected State.infos
map
Kyle Miller (Jul 17 2024 at 18:05):
Eric Wieser said:
Since right now, the diff can compute a diff in a position which isn't hoverable in the infoview, and so no diff appears
Hmm, the diff code assumes that positions really do correspond to subexpressions...
Kyle Miller (Jul 17 2024 at 18:08):
Regarding non-hierarchical positions, they only really show up in a couple places: structure instance fields, so you can hover over x
and y
in {x := 1, y := 2}
, and on binders.
Kyle Miller (Jul 17 2024 at 18:10):
Something that would be more robust would be if the diff code left mdata nodes in the expression with pp
configuration
Kyle Miller (Jul 17 2024 at 18:17):
Eric Wieser said:
Since right now, the diff can compute a diff in a position which isn't hoverable in the infoview, and so no diff appears
Did you run into cases that aren't literals? Arguably the diff routine should know about OfNat expressions.
Eric Wieser (Jul 17 2024 at 18:38):
The case I was trying to handle was display the diff between a_very_long_name + another_long_name
and a_very_long_name - another_long_name
as just on the +
/ -
character, though obviously that's not the same example as the one I summarize above.
Kyle Miller (Jul 17 2024 at 18:42):
For that, if you add pp.tagAppFns
at the position of a + b
/a - b
, it'll make +
and -
hoverable, though I think the Pos will be for HAdd.hAdd
and HSub.hSub
Eric Wieser (Jul 17 2024 at 18:44):
Do you think it would be reasonable for the diffing machinery to do this automatically?
Kyle Miller (Jul 17 2024 at 18:44):
You can at least do set_option pp.tagAppFns true
to experiment to see if it works, without spending time trying to make the option be precisely set
Eric Wieser (Jul 17 2024 at 18:49):
Great, thanks!
Eric Wieser (Jul 17 2024 at 18:49):
In particular, I'm thinking about things like fooHom x y
vs foo x y
, where seeing only the function application changing would be helpful
Kyle Miller (Jul 17 2024 at 18:52):
Eric Wieser said:
Do you think it would be reasonable for the diffing machinery to do this automatically?
I'm wondering if diffing should be "inside" the delaborator, like a variant of docs#Lean.PrettyPrinter.delabCore that takes two expressions and annotates expressions in a delaborator-aware way. Note for example that delabCore can do transformations like beta reduction or metavariable instantiation (plus, some delaborators do eta reduction of certain terms).
Or, there's docs#Lean.Meta.addPPExplicitToExposeDiff, which adds pp.explicit
meta nodes to show differences. It's still trying to recapitulate the delaborator by making educated guesses of where pp.explicit
s are needed, but at least it's not messing around with getting positions right.
Kyle Miller (Jul 17 2024 at 18:53):
I could see something like addPPExplicitToExposeDiff that inserts annotations (including tagAppFns if the differences is on the function), and then having a post-delaboration pass that works on Syntax directly, if you want to mark differences with colors.
Kyle Miller (Jul 17 2024 at 18:54):
It might take some fixes to core delaborators to make sure these annotations are respected in all cases, which I think we can allocate some resources doing.
Last updated: May 02 2025 at 03:31 UTC