@@ -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: *)
464465Ltac2 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:) *)
477478Ltac2 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: *)
495482Ltac2 Eval ltac1:(ltac2:(printf "hello from Ltac2 inside Ltac1")).
0 commit comments