Skip to content

Ltac2 Quotation tutorial#123

Merged
thomas-lamiaux merged 6 commits intorocq-prover:mainfrom
SkySkimmer:ltac2-quot
Feb 26, 2026
Merged

Ltac2 Quotation tutorial#123
thomas-lamiaux merged 6 commits intorocq-prover:mainfrom
SkySkimmer:ltac2-quot

Conversation

@SkySkimmer
Copy link
Copy Markdown
Contributor

Close #93

Copy link
Copy Markdown
Collaborator

@thomas-lamiaux thomas-lamiaux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The content is clear to me.

However, it is more of an explanation than a tutorial since it is not much about doing.

A tutorial is a practical activity, in which the student learns by doing something meaningful, towards some achievable goal.

Would there be not trivial but simple enough examples that could be added to 2.1 and 2.4 to showcase how the need for quoting arises in practice, and how you choose constr, open_constr etc...

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

Reading the tutorial I don't get when we want to use const:, I understand open_constr is more expressive and perform better ? by the way, is open_constr econstr ?

@SkySkimmer
Copy link
Copy Markdown
Contributor Author

is open_constr econstr ?

This is not a sensible question. open_constr is syntax, econstr is a type.

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

just curious you know

@SkySkimmer
Copy link
Copy Markdown
Contributor Author

Curious about what? I can only answer questions that I can understand.

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

Reading the tutorial I don't get when we want to use const:, I understand open_constr is more expressive and perform better ? by the way, is open_constr econstr ?

what about that ?

@SkySkimmer
Copy link
Copy Markdown
Contributor Author

IDK how often constr:() is useful.

by the way, is open_constr econstr ?

open_constr is ltac2 syntax, econstr is a ocaml type, how could they be the same?

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

My question is rather when should you use constr rather than open_constr

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

@SkySkimmer could you read section 2, and tells me if it looks good to you ?
Btw is unquoting $ explained somewhere ? I don't remember so

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

Also is Control.hyp quoting ?

@SkySkimmer
Copy link
Copy Markdown
Contributor Author

Control.hyp is just a function.

We can do so by:
1. Recovering the type [?a] by matching the type of the hypothesis
2. Creating a new existantial variables with [(_ :> a)],
3. Quoting it [let e := '(_ :> ?a)] to get a Ltac2 expression we can manipulate
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
3. Quoting it [let e := '(_ :> ?a)] to get a Ltac2 expression we can manipulate
3. Quoting it [let e := '(_ :> $a)] to get a Ltac2 expression we can manipulate

Copy link
Copy Markdown
Contributor Author

@SkySkimmer SkySkimmer Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also the let is not part of the quoting
and what we manipulate is the ltac value produced by evaluating the expression, not the expression itself

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your change does not adress my comment IMO
stop talking about manipulating expressions

Comment on lines +224 to +225
The reasons is that to solve existantial variables, opposite to [open_constr:],
[constr:] runs typeclass inference.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's the reason, these evars are not typeclass evars.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "instance" is just what we call a possible value for an evar

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment still incorrectly mentions TC inference.

Comment on lines +275 to +294
(** As an example, consider writing a small function [exists].
If we write a notation for it naively, then it will fail when linked with
[;] with another tactic, because there will be two goals:
*)

Ltac2 exists0 (t : constr) :=
unshelve (econstructor 1) > [exact $t |].

Ltac2 Notation "exists" t(constr) := exists0 t.

Goal {n | n <= 0} * {n | n <= 0}.
Fail split; exists 0.
Abort.

(** We need to postpone typechecking to after focusing the goals.
We can do so by quoting a [preterm] rather than a [constr], then typechecking by hand.
*)

Ltac2 Notation "exists" t(preterm) :=
Control.enter (fun () => exists0 (Constr.pretype t)).
Copy link
Copy Markdown
Contributor Author

@SkySkimmer SkySkimmer Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the proper way to postpone typechecking is to thunk ie

Ltac2 Notation "exists" t(thunk(constr)) :=
  Control.enter (fun () => exists0 (t ())).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last comment to adress, not sure what you mean. Are you saying this is a bad example ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's rather anti-idiomatic I think
in general if you're just going to call Constr.pretype there's no real need for preterm
you need to be changing flags or expected type somehow for preterm to be useful

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jpoiret this example was yours

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to remove the example for now, and merge

Co-authored-by: Gaëtan Gilbert <gaetan.gilbert@skyskimmer.net>
@thomas-lamiaux thomas-lamiaux merged commit 5abb1fa into rocq-prover:main Feb 26, 2026
1 check failed
@SkySkimmer SkySkimmer deleted the ltac2-quot branch February 26, 2026 15:19
Copy link
Copy Markdown
Member

@gares gares left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments up to 2.2

The grammar of names may be trivial but it still needs some syntax
to produce name constants in Ltac2 expression.

Identifiers are of type [ident], and can be create using [@x]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Identifiers are of type [ident], and can be create using [@x]
Identifiers are of type [ident], and can be created using [@x]

(** A term [t] is quoted in two steps:

1. The term is internalized when the Ltac2 expression is typechecked.
This does several things like name resolution or interpreting notations.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I suggest: notation unfolding and binding analysis (locally bound v.s. global reference).


2. When the Ltac2 expression is evaluated, the internalization of [t]
is typechecked in the current context, returning the elaborated term.
See " type inference" through the glossary index in the reference manual.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
See " type inference" through the glossary index in the reference manual.
See "type inference" through the glossary index in the reference manual.

is typechecked in the current context, returning the elaborated term.
See " type inference" through the glossary index in the reference manual.

Note that ['] does not run typeclass inference.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires an example. Also the next sentence seems to be an example of this, which is not.

Comment on lines +120 to +121
hypotheses), it throws an error if more than one goal is focused.
For instance, the following fails as there are two goals after [split]:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pick two goals with different context, otherwise you are shooting yourself in the foot.

Fail split; let _ := '(0) in ().
Abort.

(** Moreover, this error is "thrown", meaning it cannot be caught by "try" and
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(** Moreover, this error is "thrown", meaning it cannot be caught by "try" and
(** Moreover, this error is fatal, meaning it cannot be caught by "try" and

Comment on lines +160 to +162
[$(Control.hyp h)] or variation of that. It is only possible to unquote variables.
The reason is that functions like [Control.hyp] needs a goal, where [$] does not.
You hence need a [ltac2:()] wrapper, c.f. section 3.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be clarified further, since in the example above there is a context.
It is not clear to me why doing a let-elimination in the code above would result in a failure.


(** We can also wrap it in a notation, to do the quoting for us *)

Ltac2 Notation "forward" h(ident) := forward h.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be used earlier as a method to avoid the various @ e co?

@gares
Copy link
Copy Markdown
Member

gares commented Mar 3, 2026

I'm sorry I did not realize the PR was already merged.

@thomas-lamiaux
Copy link
Copy Markdown
Collaborator

Still useful I guess, maybe open issue to say they are stuff to improve and link the comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ltac2: Write a tuto on Quoting

4 participants