Zulip Chat Archive
Stream: lean4 dev
Topic: Multiply delayed assignments?
Rish Vaishnav (Sep 14 2022 at 02:54):
Hi, I've gotten sucked into the MetavarContext.lean
file (I know it's "ancient" at this point haha, just really want to get a handle on something relating to metavariables before I move on to frontend stuff) and I understand most of the motivation behind the code there at this point. One thing that has puzzled me a bit however, is this part of elimMVar
:
/- If `mvarId` is the lhs of a delayed assignment `?m #[x_1, ... x_n] := ?mvarPending`,
then `nestedFVars` is `#[x_1, ..., x_n]`.
In this case, `newMVarId` is also `syntheticOpaque` and we add the delayed assignment delayed assignment
```
?newMVar #[y_1, ..., y_m, x_1, ... x_n] := ?m
```
where `#[y_1, ..., y_m]` is `toRevert` after `collectForwardDeps`.
-/
let (mvarIdPending, nestedFVars) ← match (← getDelayedMVarAssignment? mvarId) with
| none => pure (mvarId, #[])
| some { fvars, mvarIdPending } => pure (mvarIdPending, fvars)
assignDelayedMVar newMVarId (toRevert ++ nestedFVars) mvarIdPending
Like, I understand exactly what we're doing here -- we're just extending the free variables that come from the original delayed assignment with toRevert
from this one, and then associating it with the same underlying original metavariable. And I know how this case can arise in terms of how the function is called, if we call it first on a syntheticOpaque
metavar with some free variables xs
in the context, and then call it later on the resulting delayed assigned metavariable with a set of free variables ys
that includes some free variables not in xs
. I'm just trying to wrap my head around when exactly this would arise. Are there any MWEs you know of that fall into this case? Also having some concrete examples to walk through would really help me out with my understanding of this file hahaha. Thanks!
Rish Vaishnav (Sep 14 2022 at 02:56):
(also lmk if this topic is better suited for the general Lean 4 stream, not sure if this is the right place for newbie questions relating to things not being actively developed atm)
Leonardo de Moura (Sep 14 2022 at 03:24):
@Rish Vaishnav Happy to do a walkthrough of the MetavarContext.lean
in our next front-end meeting. It may also be a good opportunity to document the file better and simplify the implementation.
Not sure I fully understood the question, but I will try to give some pointers.
- Metavariables are holes/goals. They have a local context and a type. When we assign a value
e
to a metavariable?m
with local contextctx
, all free variables ine
must be inctx
. - Synthetic opaque metavariables
?m
are synthesized using procedures (e.g., by executing a tactic). These procedures may be on a to-do list, and are responsible for performing the assignment?m := v
- When we create a (dependent) arrow or a lambda abstraction, we convert free variables into bound variables.
- Suppose we want to create a lambda abstraction using the term
Nat.add x ?m
by abstracting the free variablex
. That is, we want to createfun x => Nat.add x ?m
. Note that, thex
in the body of the lambda is the bound variableExp.bvar 0
. Now, suppose thatx
is in the local context of?m
. Now, suppose later we assign?m := x
. We need to make sure that the free variablex
also becomesExpr.bvar 0
. Let's focus on the case?m
is a synthetic opaque metavariable. Then, we create a new metavariable?n
that does not contain the free variablex
in its local context, and we add the delayed assignment?n #[x] := ?m
. We can view this delay assignment as follows: when?m
is assigned, abstractx
and assign the result to?n
. Then, our resulting lambda isfun x => Nat.add x ?n
. - Now, suppose we want to construct
fun y => fun x => Nat.add x ?n
, andy
is in the local context of?n
. This scenario will trigger the code in your message.
To trigger the scenario, we need
- An opaque synthetic metavariable, we can create one using tactics.
- Abstract a term containing the metavariable, and then abstract the term again.
Leonardo de Moura (Sep 14 2022 at 03:35):
Here is an artificial example to reach the branch
| some { fvars, mvarIdPending } => pure (mvarIdPending, fvars)
Example:
example (x : True) : True :=
have h : True → True := fun _ => by constructor
h x
Rish Vaishnav (Sep 14 2022 at 03:45):
Thank you! Yes, a walkthough would be great, but no pressure at all if there's another topic more directly related to frontend that you wanted to talk about instead. I was just looking for a concrete example that would trigger it, so you've exactly answered my question :)
I'll have to think about that a bit more, but I'm guessing that the by constructor
tactic is what introduces the synthetic opaque metavar here?
Leonardo de Moura (Sep 14 2022 at 03:47):
If we put an assert! false
in the branch above. That is,
| some { fvars, mvarIdPending } => assert! false; pure (mvarIdPending, fvars)
and then execute the example in the debugger with LEAN_ABORT_ON_PANIC
set,
~/projects/lean4/build/release (master) $ LEAN_ABORT_ON_PANIC=1 gdb stage1/bin/lean
...
(gdb) run mvarEx.lean
Where mvarEx.lean
contains the example above, we get a stack trace
Starting program: /home/leodemoura/projects/lean4/build/release/stage1/bin/lean mvarEx.lean
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
PANIC at _private.Lean.MetavarContext.0.Lean.MetavarContext.MkBinding.elimMVar Lean.MetavarContext:1075:45: assertion violation: false
backtrace:
/home/leodemoura/projects/lean4/build/release/stage1/bin/../lib/lean/libleanshared.so(lean_panic_fn+0xa3)[0x7ffff7b21a33]
/home/leodemoura/projects/lean4/build/release/stage1/bin/../lib/lean/libleanshared.so(l_panic___at___private_Lean_MetavarContext_0__Lean_MetavarContext_MkBinding_elimMVar___spec__6+0x19)[0x7ffff78a59f9]
...
/home/leodemoura/projects/lean4/build/release/stage1/bin/../lib/lean/libleanshared.so(l_Lean_Meta_mkLambdaFVars+0x400)[0x7ffff69049f0]
...
/home/leodemoura/projects/lean4/build/release/stage1/bin/../lib/lean/libleanshared.so(l_Lean_Elab_Term_elabMutualDef_go___lambda__3+0x3
...
That is, we got the assertion when trying to abstract the (x : True)
here
https://github.com/leanprover/lean4/blob/master/src/Lean/Elab/MutualDef.lean#L248
Leonardo de Moura (Sep 14 2022 at 03:47):
I'll have to think about that a bit more, but I'm guessing that the by constructor tactic is what introduces the synthetic opaque metavar here?
Correct.
Leonardo de Moura (Sep 14 2022 at 03:48):
The first abstraction occurs at fun _ => by constructor
, and the second when abstracting (x : True)
.
Rish Vaishnav (Sep 14 2022 at 03:52):
Thank you very much! I'm going to give this another pass tomorrow, and try out that gdb
run for myself.
Rish Vaishnav (Sep 17 2022 at 22:59):
Leonardo de Moura said:
Here is an artificial example to reach the branch
| some { fvars, mvarIdPending } => pure (mvarIdPending, fvars)
Example:
example (x : True) : True := have h : True → True := fun _ => by constructor h x
Is there some code/documentation I can read into to better understand the process/rationale of creating an opaque synthetic metavariable here?
Leonardo de Moura (Sep 18 2022 at 13:26):
@Rish Vaishnav I am not exactly sure what the question is. We can start the next frontend meeting (on Tuesday) discussing that. I think this is an important topic, and we would all benefit from additional documentation.
Rish Vaishnav (Sep 18 2022 at 13:30):
No worries! Yes that sounds like a great plan for Tuesday.
Rish Vaishnav (Sep 18 2022 at 13:49):
I suppose I could rephrase my question as: which file is the logic that makes a synthetic opaque metavar for the by constructor
tactic in the example above defined in? Is that part of the logic for the constructor
tactic itself, or the more general tactic framework?
Rish Vaishnav (Sep 18 2022 at 13:50):
(go-to-definition on constructor
didn't work for me)
Leonardo de Moura (Sep 18 2022 at 13:57):
The constructor
tactic is a small wrapper around apply
https://github.com/leanprover/lean4/blob/master/src/Lean/Meta/Tactic/Constructor.lean#L25
The apply
tactic is creating the opaque metavariables here: https://github.com/leanprover/lean4/blob/master/src/Lean/Meta/Tactic/Apply.lean#L140
Rish Vaishnav (Sep 18 2022 at 13:58):
Ah, thank you! I'll investigate those files.
Last updated: Dec 20 2023 at 11:08 UTC