Skip to content

Commit d0db0f1

Browse files
small comments
1 parent 1ca8aa9 commit d0db0f1

1 file changed

Lines changed: 6 additions & 19 deletions

File tree

src/metaprogramming/ltac2/tutorial_quoting.v

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ Ltac2 absurd () :=
157157
end.
158158

159159
(** As an important technical point, note it is not possible to directly write
160-
[$(Control.hyp h)]. It is only possible to unquote variables.
161-
The reason is that ???
160+
[$(Control.hyp h)] or variation of that. It is only possible to unquote variables.
161+
The reason is that functions like [Control.hyp] needs a goal, where [$] does not.
162+
You hence need a [ltac2:()] wrapper, c.f. section 3.
162163
*)
163164

164165
(** ['] is an notation for [open_constr:]. The name [open_constr] comes
@@ -171,7 +172,7 @@ Ltac2 absurd () :=
171172
We can do so by:
172173
1. Recovering the type [?a] by matching the type of the hypothesis
173174
2. Creating a new existential variables with [(_ :> $a)],
174-
3. Quoting it [let e := '(_ :> $a)] to get a Ltac2 expression we can manipulate
175+
3. Quoting it [let e := '(_ :> $a)] to get a Ltac2 expression [e] we can manipulate
175176
4. Specialize the hypothesis [h] with [specialize ($h $e)]
176177
5. Following these steps, the existential variable is shelved.
177178
Therefore, to create a goal [A], we wrap the expression in [unshelve].
@@ -221,8 +222,7 @@ Fail Ltac2 Eval constr:(_).
221222
222223
As you may have noticed, the error message above is referring to instances:
223224
"Could not find an instance for the following existential variables: ?y : ?T".
224-
The reasons is that to solve existential variables, unlike [open_constr:],
225-
[constr:] runs typeclass inference.
225+
The reasons is that unlike [open_constr:], [constr:] runs typeclass inference.
226226
227227
Another difference is that [constr:(...)] substitutes all defined evars by
228228
their bodies in the returned term. Because defined evars are
@@ -459,6 +459,7 @@ Ltac2 Notation "##" x(preterm) := Constr.pretype x.
459459
(** ** 5. Ltac1 and Ltac2
460460
461461
We can embed a Ltac1 expression into Ltac2 using [ltac1:(...)].
462+
This can be practical, for instance, for transitioning from Ltac1 to Ltac2.
462463
The resulting Ltac2 expression has type [unit], and evaluating it
463464
runs the Ltac1 tactic: *)
464465
Ltac2 Eval ltac1:(idtac "hello from Ltac1").
@@ -476,20 +477,6 @@ Ltac2 Eval ltac1:(x y |- idtac y) (Ltac1.of_constr '42) (Ltac1.of_ident @xx).
476477
current goal, so it produces no output when there are no goals:) *)
477478
Ltac2 Eval ltac1:(x y |- idtac x y) (Ltac1.of_constr '42) (Ltac1.of_ident @xx).
478479

479-
(** We can also produce values of type [Ltac1.t] by quoting Ltac1
480-
expressions with [ltac1val:(...)] (which supports the same
481-
[ltac1val:(v1 .. vn |- ...)] syntax to quantify over variables): *)
482-
Ltac2 Eval ltac1val:(let x := constr:(42) in x).
483-
484-
(** Such values can be cast to Ltac2 types using the APIs in module
485-
[Ltac2.Ltac1]. Since Ltac1 is dynamically typed such casts can
486-
fail (returning None).
487-
488-
Ltac1 semantics of returning values are way beyond the scope of
489-
this tutorial, and for instance the following ltac1val is NOT a
490-
constr and the cast returns [None]: *)
491-
Ltac2 Eval Ltac1.to_constr ltac1val:(let x := constr:(42) in x).
492-
493480
(** We can also embed Ltac2 inside Ltac1 using [ltac2:(...)] which
494481
runs the Ltac2 tactic when evaluated: *)
495482
Ltac2 Eval ltac1:(ltac2:(printf "hello from Ltac2 inside Ltac1")).

0 commit comments

Comments
 (0)