I'm kind of stuck trying to write some ltac2 tactics while reusing ltac1 tactics from an existing codebase. Is any of these things possible?
You have to go full CPS, as is the norm in Ltac1 (à la ring)
that is, given a Ltac1 CPS-style constr, if you want to extract the result you can pass it a Ltac2 function setting a Ltac2 reference
ah, that, I tried, but couldn't get to work
Well, if you have a simple use case I can try to have a look.
I couldn't figure how to thread the name to the reference through the ltac2 callback into the ltac1 quotation
alright, I'll put something together
From Ltac2 Require Import Ltac2.
From Ltac2 Require Import Option.
Ltac tac cont :=
match goal with |- ?x = _ => cont x end.
Goal 0 = 1.
let r := { contents := None } in
let set_r (c: constr) := r.(contents) := Some(c) in
ltac1:(set_r |- tac set_r) set_r. (* does not work: set_r is not a Ltac1.t *)
something like this? I'm not sure how to turn the ltac2 callback into a Ltac1.t
So indeed, I don't know how to pass higher-order values across quotations, and as such I think it's an instance of https://github.com/coq/coq/issues/12871
The problem with this kind of feature request is that the runtime of Ltac1 is literal madness, and I am unsure of how expose this to Ltac2 without breaking soundness.
Returning values from Ltac1 is quite tricky in general...
I wonder if a function abstract : (Ltac1.t -> Ltac1.t) -> Ltac1.t
would be enough...
right, I was thinking about that
(Ltac1.t list -> Ltac1.t) -> Ltac1.t
maybe?
The comment in the issue is correct, that is there is an asymmetry between Ltac1 and Ltac2.
Since Ltac1 is untyped you can wreak havoc there.
@Armaël Guéneau nope, you need the arity.
so, int -> (Ltac1.t list -> Ltac1.t) -> Ltac1.t
where the size of the list is guaranteed to be the integer argument.
ah, right. I think that would be very useful already
but that function can be derived from the other one.
(I wouldn't go as far as saying that nested functions behave as expected in Ltac1, but it seems not totally unreasonable)
oh, right…
I insist: the Ltac1 runtime is a hellish nightmare.
But this abstraction functions seems reasonable enough. If it's enough for your need then I can write a PR (hopefully fixing the other issue as well).
yeah, it would be enough for me! if you can make a PR that'd be awesome
Writing that function is easy, but guaranteeing that it will behave as expected is not a strong promise.
Hm, I am pretty sure there was a similar hack written somewhere in the codebase but I can't find it again.
Found it: it's Tacentries.ml_val_tactic_extend.
Since Ltac1 is untyped you can wreak havoc there.
@Pierre-Marie Pédrot if it were that simple, at least you'd have the research on gradual typing to draw on
But that only deals with runtime type errors, not with global mutable state or whatnot
See https://github.com/coq/coq/pull/13442.
As usual with Ltac1, there are a lots of hoop jumping.
Last updated: Oct 13 2024 at 01:02 UTC