Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: syntax and delaborator for delayed assignment metavariables #3494

Closed
wants to merge 3 commits into from

Conversation

kmill
Copy link
Collaborator

@kmill kmill commented Feb 25, 2024

It's often confusing how fun x y => ?foo elaborates as fun x y => ?m.123 x y, with no way to see how ?m.123 is connected to ?foo. This PR adds syntax for delayed assignment metavariables, where the elaborated result pretty prints as fun x y => ?foo(x, y) instead. Hovering over the expression still shows the underlying ?m.123 x y term, and hovering over foo shows whatever foo might be currently assigned to, if anything. The syntax can be turned off with set_option pp.mvars.delayed false.

This also adds an elaborator for ?foo(x := a, y := b) syntax to create a new delayed assignment metavariable from a metavariable, making the pretty printed syntax elaboratable. In addition to being for making pretty printing round trip, it is filling in a missing feature, since, as a user, it's impossible to use synthetic holes in incompatible local contexts without being able to specify delayed assignments. For example, with the ?foo above we can then later refer to fun x y => ?foo(x, y) (where ?foo(x, y) is short for ?foo(x := x, y := y)), even though the x and y binders are totally new fvars.

The syntax is chosen to (1) use parentheses with no whitespace since that is reserved for new syntax, (2) to resemble structure instance notation, and (3) to be something like the Lean version of lambda calculus substitution (and in any case, square brackets are already used by GetElem).

@kmill kmill requested a review from Kha as a code owner February 25, 2024 06:02
@github-actions github-actions bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Feb 25, 2024
@leanprover-community-mathlib4-bot
Copy link
Collaborator

leanprover-community-mathlib4-bot commented Feb 25, 2024

Mathlib CI status (docs):

  • ❗ Std/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase a3596d953d84b3493daccdc38bd2889e817efe19 --onto 5b15e1a9f3c0d1283df7f2e2f3f1b1dc59f92cf6. (2024-02-25 06:21:04)
  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase f35c562ef8404c69aa758ddf9483a617de863870 --onto 5f70c1ca64a2c05a5866c47b9eb80a92034433ec. (2024-07-12 18:54:28)

@ericrbg-harmonic
Copy link

Will we be able to limit the scope of the metavariable in this way? e.g. ?foo(x) from your example above

@kmill
Copy link
Collaborator Author

kmill commented Feb 29, 2024

@ericrbg-harmonic It lets you write ?foo(x) to assign just a value for x, but to be clear y is still in its context and you can only do this if ?foo's y is still a local variable in the current scope.

@digama0
Copy link
Collaborator

digama0 commented Mar 2, 2024

I am concerned about the size of this expression, as I often see these metavariables in printouts and I generally don't actually care about the values of the arguments and only the fact that it is a metavariable (possibly an unassignable metavariable) is relevant to me. Maybe ?m(...) should be printed instead under some pp option? Maybe it should also be default-enabled?

@kmill kmill marked this pull request as draft July 12, 2024 18:19
@kmill kmill force-pushed the pp_delayed_assignment branch from 195ce1c to 7b90837 Compare July 12, 2024 18:23
@kmill kmill force-pushed the pp_delayed_assignment branch from 7b90837 to c4ee28d Compare July 12, 2024 18:34
@leodemoura leodemoura force-pushed the master branch 2 times, most recently from 32d60c5 to 696f70b Compare July 20, 2024 02:58
kmill added a commit to kmill/lean4 that referenced this pull request Oct 7, 2024
Where before we had
```lean
#check fun x : Nat => ?a
-- fun x ↦ ?m.7 x : (x : Nat) → ?m.6 x
```
Now by default we have
```lean
#check fun x : Nat => ?a
-- fun x => ?a : (x : Nat) → ?m.6 x
```
in particular, delayed assignment metavariables such as `?m.7` pretty print using the name of the metavariable they are delayed assigned to, suppressing the arguments used in the delayed assignment (hence `?a` rather than `?a x`). Hovering over `?a` shows `?m.7 x`.

The benefit is that users can see the user-provided name in local contexts.

The original pretty printing behavior can be recovered using `set_option pp.mvars.delayed true`.

This PR also extends the documentation for holes and synthetic holes, with useful high-level technical details about what delayed assignments are.

(This PR supercedes leanprover#3494, which has a round-trippable notation for delayed assignments. The notation in this PR is unlikely to round trip, but it is better than the current situation, where delayed assignment metavariables never round trip.)
github-merge-queue bot pushed a commit that referenced this pull request Oct 8, 2024
Where before we had
```lean
#check fun x : Nat => ?a
-- fun x ↦ ?m.7 x : (x : Nat) → ?m.6 x
```
Now by default we have
```lean
#check fun x : Nat => ?a
-- fun x => ?a : (x : Nat) → ?m.6 x
```
In particular, delayed assignment metavariables such as `?m.7` pretty
print using the name of the metavariable they are delayed assigned to,
suppressing the bound variables used in the delayed assignment (hence
`?a` rather than `?a x`). Hovering over `?a` shows `?m.7 x`.

The benefit is that users can see the user-provided name in local
contexts. A justification for this pretty printing choice is that `?m.7
x` is supposed to stand for `?a`, and furthermore it is just as opaque
to assignment in defeq as `?a` is (however, when synthetic opaque
metavariables are made assignable, delayed assignments can be a little
less assignable than true synthetic opaque metavariables).

The original pretty printing behavior can be recovered using `set_option
pp.mvars.delayed true`.

This PR also extends the documentation for holes and synthetic holes,
with some technical details about what delayed assignments are. This
likely should be moved to the reference manual, but for now it is
included in this docstring.

(This PR is a simplified version of #3494, which has a round-trippable
notation for delayed assignments. The pretty printing in this PR is
unlikely to round trip, but it is better than the current situation,
which is that delayed assignment metavariables never round trip, and
plus it does not require introducing a new notation.)
@kmill kmill closed this Oct 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants