Zulip Chat Archive

Stream: lean4 dev

Topic: ElabTermM and saveState


Joachim Breitner (Nov 10 2023 at 12:43):

I want to store the state of my currentElabTermM context and resume it later. If I write

      let savedState  saveState
      restoreState savedState

that seems to be a proper no-op, as expected. But if I saveState in two different places, and then restore them later, I get unknown free variable '.
Is saveState here not a good way of doing that?

(Sorry for begin rather vague, I should try to #mwe this issue.)

Joachim Breitner (Nov 10 2023 at 13:00):

Here is a #mwe that doesn’t quite reproduce the issue I am facing, but certainly demonstrates a misunderstanding on my side:

import Mathlib.Tactic.RunCmd
open Lean Elab Term Command Meta

set_option autoImplicit false

elab (name := demo) "demo" : command => liftTermElabM do
    let expr  elabTerm ( `(term|fun x => x)) none
    let Expr.lam n d b c := expr | unreachable!
    let (body,s)  withoutModifyingState $ withLocalDecl n c d fun x => do
        let b' := b.instantiate1 x
        check b'
        dbg_trace "Inside : {((← getLCtx).find? b'.fvarId!).isSome}"
        pure (b',  saveState)
    -- let (_body,_s) ← withoutModifyingState $  withLocalDecl n c d fun x => do
    --     let b' := b.instantiate1 x
    --     check b'
    --     pure (b', ← saveState)
    -- variable is not available, this is expected:
    dbg_trace "Outside 1: {((← getLCtx).find? body.fvarId!).isSome}"
    check body -- shouldn't this fail, because the local decl is not available
    restoreState s
    -- variable still not available, this is unexpected
    dbg_trace "Outside 2: {((← getLCtx).find? body.fvarId!).isSome}"
    dbg_trace "{body}"

demo

The b' inside the withLocalDecl is the FVar that was introduced by withLocalDecl. It is in scope, as the dbg_trace shows.
Outside, it is no longer part of the of the environment, as expected. (Oddly, check doesn’t complain).
But after restoreSTate is it still not part of the local context. Why?

Joachim Breitner (Nov 10 2023 at 13:02):

Ah, saveState and restore doesn’t actually touch the MetaM Context! Does that mean that these states are not meant to be restored in a different context?

Joachim Breitner (Nov 10 2023 at 13:07):

So this looks like it might work; I am not sure how kosher that is:

import Mathlib.Tactic.RunCmd
open Lean Elab Term Command Meta

set_option autoImplicit false

elab (name := demo) "demo" : command => liftTermElabM do
    let expr  elabTerm ( `(term|fun x => x)) none
    let Expr.lam n d b c := expr | unreachable!
    let (body,s,mc)  withoutModifyingState $ withLocalDecl n c d fun x => do
        let b' := b.instantiate1 x
        check b'
        dbg_trace "Inside : {((← getLCtx).find? b'.fvarId!).isSome}"
        pure (b',  saveState,  readThe Meta.Context)
    -- let (_body,_s) ← withoutModifyingState $  withLocalDecl n c d fun x => do
    --     let b' := b.instantiate1 x
    --     check b'
    --     pure (b', ← saveState)
    -- variable is not available, this is expected:
    dbg_trace "Outside 1: {((← getLCtx).find? body.fvarId!).isSome}"
    check body -- shouldn't this fail, because the local decl is not available
    withTheReader Meta.Context  (fun _ => mc) $ do
      restoreState s
      -- variable still not available, this is unexpected
      dbg_trace "Outside 2: {((← getLCtx).find? body.fvarId!).isSome}"
      dbg_trace "{body}"

demo

Jannis Limperg (Nov 10 2023 at 13:45):

Looks okay to me, though not exactly idiomatic. I would save the LocalContext in which body is valid, rather than the MetaM.Context.

Joachim Breitner (Nov 10 2023 at 14:24):

Hmm, make sense, but I’d be worried about breaking invariants, e.g. between lctx and localInstances then:

structure Context where
  config            : Config               := {}
  /-- Local context -/
  lctx              : LocalContext         := {}
  /-- Local instances in `lctx`. -/
  localInstances    : LocalInstances       := #[]

Jannis Limperg (Nov 10 2023 at 16:13):

Ah yes, you'll need the LocalInstances as well. But withLCtx would have told you this as well.

Jannis Limperg (Nov 10 2023 at 16:14):

Other than that, I don't think there are any invariants attached to LocalContext; after all, withContext is an ever-popular function.

Joachim Breitner (Nov 10 2023 at 16:16):

Thanks! Changed accordingly.


Last updated: Dec 20 2023 at 11:08 UTC