Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: Collect all dependencies required for an expression


Leni Aniva (Aug 25 2025 at 14:01):

Is there a function that collects all fvars that are required for an expression to make sense?

e.g., if I have

b : a
c : b

and the expression is f c, then both b and c would need to exist for this expression to make sense. However, collectFVars only collects c.

Jannis Limperg (Aug 25 2025 at 14:38):

I'm not aware of such a function.

In case it helps, I believe the specific situation you mention is not possible because f cannot be typed without mentioning b (i.e., @f b c), except if f is itself an fvar. Maybe there's an invariant here that can be exploited. Another corner case is unassigned mvars; there you'll have to assume that any fvar mentioned in the mvar's local context could potentially be used.

Kyle Miller (Aug 25 2025 at 14:45):

First thing that comes to mind is that you could add e := f c to the local context then use Lean.Meta.collectForwardDeps on every preexisting local variable. The set of local variables that have e as a forward dependency consist of the minimal context for f c. This handles mvars too.

Leni Aniva (Aug 25 2025 at 15:26):

Jannis Limperg said:

I'm not aware of such a function.

In case it helps, I believe the specific situation you mention is not possible because f cannot be typed without mentioning b (i.e., @f b c), except if f is itself an fvar. Maybe there's an invariant here that can be exploited. Another corner case is unassigned mvars; there you'll have to assume that any fvar mentioned in the mvar's local context could potentially be used.

assume f is a constant

Aaron Liu (Aug 25 2025 at 15:40):

def foo (n : Nat) : Type := Nat

example (n : Nat) (m : foo n) : Nat.isValidChar m := by
  -- in this context the goal does not mention `n`
  -- but the type of `m` depends on `n`
  -- `Nat.isValidChar` is a constant
  trace_state
  sorry

Leni Aniva (Aug 25 2025 at 15:50):

I see what you mean. The example I showed I above is a bad one. This would make more sense:

b : a
c : b
d : a = (some function of c)

and the expr is f d. In this case b and c are also dependencies. Or if the expr is just c, in which case b must also be a dependency.

Aaron Liu (Aug 25 2025 at 15:57):

What is your use case for this function?

Leni Aniva (Aug 25 2025 at 15:57):

Aaron Liu said:

What is your use case for this function?

determine the minimal context for an expression

Aaron Liu (Aug 25 2025 at 16:04):

I found docs#Lean.findExprDependsOn

Aaron Liu (Aug 25 2025 at 16:06):

this would be great if the arguments pf and pm were monadic (but I guess then you wouldn't be able to cache it)

Leni Aniva (Aug 25 2025 at 16:08):

Aaron Liu said:

I found docs#Lean.findExprDependsOn

This doesn't work for the case where the expr is just c

Leni Aniva (Aug 25 2025 at 16:08):

It does not signal that b is a dependency

Aaron Liu (Aug 25 2025 at 16:08):

I found docs#Lean.Expr.getMVarDependencies

Aaron Liu (Aug 25 2025 at 16:08):

it only works for mvar dependencies

Aaron Liu (Aug 25 2025 at 16:12):

You could loop through the local context in reverse and docs#Lean.MVarId.tryClear everything

Kyle Miller (Aug 25 2025 at 16:15):

I'll mention again that you can do Lean.Meta.collectForwardDeps on everything in the local context to figure out the correct dependencies. Adding the expression as a let variable is a trick to then let this computation process all the fvars and metavariables in your expression correctly.

Kyle Miller (Aug 25 2025 at 16:18):

Or there's the weird mkLambdaFVars (<- getLCtx).getFVars e (usedOnly := true), but you'll lose the connection to which fvar was actually used. It probably also needs a step to clear aux decls from the local context first.


Last updated: Dec 20 2025 at 21:32 UTC