Skip to Content.
Sympa Menu

coq-club - Re: [Coq-Club] help calling ltac1 function from ltac2

coq-club AT inria.fr

Subject: The Coq mailing list

List archive

Re: [Coq-Club] help calling ltac1 function from ltac2


Chronological Thread 
  • From: Jason Gross <jasongross9 AT gmail.com>
  • To: coq-club <coq-club AT inria.fr>
  • Cc: Tej Chajed <tchajed AT mit.edu>
  • Subject: Re: [Coq-Club] help calling ltac1 function from ltac2
  • Date: Sun, 16 Aug 2020 14:09:38 -0400
  • Authentication-results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=jasongross9 AT gmail.com; spf=Pass smtp.mailfrom=jasongross9 AT gmail.com; spf=None smtp.helo=postmaster AT mail-ej1-f49.google.com
  • Ironport-phdr: 9a23:qewF5B1/RgyAudAGsmDT+DRfVm0co7zxezQtwd8ZseMWLvad9pjvdHbS+e9qxAeQG9mCtbQd07Od6vmxEUU7or+5+EgYd5JNUxJXwe43pCcHRPC/NEvgMfTxZDY7FskRHHVs/nW8LFQHUJ2mPw6arXK99yMdFQviPgRpOOv1BpTSj8Oq3Oyu5pHfeQpFiCe8bL9oMRm6sRjdusYLjYd/Lqs61wfErGZPd+lK321jOEidnwz75se+/Z5j9zpftvc8/MNeUqv0Yro1Q6VAADspL2466svrtQLeTQSU/XsTTn8WkhtTDAfb6hzxQ4r8vTH7tup53ymaINH2QLUpUjms86tnVBnlgzocOjUn7G/YlNB/jKNDoBKguRN/xZLUYJqIP/Z6Z6/RYM8WSXZEUstXSidPAJ6zb5EXAuUOM+ZXrYnzqVUNoxWjGwejGPjixSVUinLsx6A2z/gtHAPA0Qc9H9wOqnPUrNDtOakWS++1167IzTPeZP1Xwzf975PIcgs8qvyLX7J/a9HRyU4pFwPKlFWQrpflPyiR2+kWvGib6vBvVeOri2I9tw5xpT2vy94qh4LUiY0b1krK+j9lwIYpO9K4Ukh7bMakHpZfsyyWKoR7Tt0hTmxstis0yr0LtIC7cSUI1ZgpyQPTZvOafoSU4h/uSPucLDZ5iX9rZr+zmgu+/Eigx+D9UMS/zVhEri1AktbWt3AN0QTe6seCSvRn/0eh3SyD2BzU6uFBOUw0laraK4Y6wrIqlpoTtkrCEynrk0v1lK+bblso9vSs5uj9YbjrpoWQO5Fphgz9KKgjlciyDOIlOQYURWeb4/6z1Lj78E35XrpKivo2n7HcsJ/AJMQbore1DBFX0oo+8hq/ATir3dACkXkIK1JFfx2Hj4z3NF3UPP/4CvK/j0ytkDdt2f/GIqXsDovRInXHirvsfrZw51RCxAYuzt1T/Z1ZB7UZLPL2QEDxtdjYDhEjMwyzxubqENd92ZkFWWKIBK+ZP7nSsViT5uI0J+SBf4AVuDPnJPgk4/7il2M2mVgYfaWxx5sYdGi4Huh6I0WeeXfjntABEX4TsgUiSOzqlUaNXCVIZ3eyWqI8/is0BJinDYfFXICtgaaO0D21Hp1MNSh6DQWHFm6tfIGZUb9YYyWLZ8RljzYsVL67SoZn2wv45yHgzL8yDOPP/StQmojkz8M9s+/ajhY0+iZzFN/M+26IRmBw2GgPQmllj+hEvUVhxwLbguBDiPtCGIkWvqsRC1poBdvn1+V/TuvKdEfBc9OOEgv0R9ynBXQ8TIt0zYNfJUl6HNqmg1bI2C/4W+ZJxYzOP4Q99+fn51a0P9x0ki+U26wojl1gScxKZzX/1/xPsjPLDouMqH230qOjdKASxinIrT7Rwm+HvUUeWwl1A/zI

> But, why doesn't this work?:

The problem is that you are throwing away the applied tactic without running it.  You have two options:
1. Make your thunk immediate, e.g., by replacing `ltac:(fun i => idtac i)` with `ltac:(fun i => match goal with _ => idtac i end)`
2. Run the tactic in the continuation of Ltac1.apply by replacing `(fun _ => ())` with `Ltac1.run`

On Sun, Aug 16, 2020 at 2:01 PM jonikelee AT gmail.com <jonikelee AT gmail.com> wrote:
On Sat, 15 Aug 2020 21:39:11 -0500
Tej Chajed <tchajed AT mit.edu> wrote:

> Here's a solution (perhaps more complicated than you were expecting):

I guess I shouldn't be embarassed that I didn't figure this one out on
my own. ;)

But, why doesn't this work?:

From Ltac2 Require Import Ltac2.

Ltac2 hyploop (tac : constr -> unit) :=
  let hypconstrs := List.map (fun (id, _, _) => Control.hyp id) (Control.hyps ()) in
  let rec loop hs :=
      match hs with
      | h :: hs => tac h; loop hs
      | _ => ()
  end in loop hypconstrs.

Ltac allhyps_fast tac :=
  let hyploop' :=
      ltac2:(t |-
         let tac2 (i: constr) := Ltac1.apply t [Ltac1.of_constr i] (fun _ => ()) in
         hyploop tac2) in
  hyploop' tac.

Set Default Proof Mode "Classic".

Goal nat -> bool -> nat.
Proof.
  intros x y.
  allhyps_fast ltac:(fun i => idtac i).
Abort.

Even staying entirely within Ltac2, if there no way more
straightforward than this ident_to_constr kludge cast to get hypotheses
as constrs instead of idents, that seems like a significant shortcoming
of Ltac2 having nothing to do with the Ltac1/Ltac2 interface.


>
> Note a significant part of the nastiness comes from not having
> Ltac1.of_ident, please complain to Pierre-Marie Pedrot that this is a
> useful feature and workarounds for it are horrendous. Otherwise the
> complications are somewhat necessary due to a bunch of higher-order
> stuff that has to back and forth between the two languages.
>
> From Ltac2 Require Import Ltac2.
>
> Ltac2 hyploop (tac : ident -> unit) :=
>   let rec loop hs :=
>       match hs with
>       | h3 :: hs => match h3 with
>                     | (h, _, _) => tac h; loop hs
>                     end
>       | _ => ()
>       end in loop (Control.hyps ()).
>
> (* ident_to_constr is a helper to serialize an identifier as a constr
> of type [unit -> unit], which uses the ident as the binder *)
> Ltac2 ident_to_constr (i:ident) :=
>   constr:(ltac2:(clear; intros $i; exact tt) : unit -> unit).
>
> Ltac allhyps_fast tac :=
>   (* tac can't be called from Ltac2 because we can't convert an ident
> to an Ltac1 dynamically typed value (the type Ltac1.t in Ltac2);
> instead, we will call a variant that expects its argument as the
> binder of a constr *) let tac_constr i_constr :=
>       lazymatch i_constr with
>       | fun i => _ => tac i
>       end in
>   (* at the outermost level, we're constructing hyploop using the
> ltac1-to-ltac2 FFI which allows passing an argument so we can pass
> tac (as [tac_constr]) to it *)
>   let hyploop :=
>       ltac2:(t |- (* t is passed as an Ltac1 opaque object of type
> [Ltac1.t]. Remember that it's an Ltac1 tactic that takes a constr and
> returns nothing. *)
>          (* we now convert the ident hyploop will pass us to an Ltac1
>          dynamically-typed bundle... *)
>          let ident_to_arg (i: ident) := Ltac1.of_constr
> (ident_to_constr i) in (* And finally construct the higher-order
> argument to hyploop using [Ltac1.apply], the most general way to call
> an Ltac1 function. The third argument is a CPS tactic to use the
> result, but these tactics passed to hyploop (thankfully) don't return
> anything. *) let tac (i: ident) := Ltac1.apply t [ident_to_arg i]
> (fun _ => ()) in hyploop tac) in
>   hyploop tac_constr.
>
> Set Default Proof Mode "Classic".
>
> Goal nat -> bool -> nat.
> Proof.
>   intros x y.
>   allhyps_fast ltac:(fun i => let P := type of i in idtac i ":" P).
>   (* prints x : nat and y : bool, as expected *)
> Abort.
>
> On Sat, Aug 15, 2020 at 8:12 PM jonikelee AT gmail.com
> jonikelee AT gmail.com <http://mailto:jonikelee AT gmail.com> wrote:
>
>
> > I have the following Ltac2 function to iterate over hypotheses:
> >
> > Ltac2 hyploop (tac : ident -> unit) :=
> >   let rec loop hs :=
> >       match hs with
> >       | h3 :: hs => match h3 with
> >                     | (h, _, _) => tac h; loop hs
> >                     end
> >       | _ => ()
> >       end in loop (Control.hyps ()).
> >
> > How do I call hyploop from Ltac1, passing in an Ltac1 function
> > for the tac argument?
> >
> > Ltac allhyps_fast tac :=
> >   ltac2:(hyploop ltac1:(????)).
> >
> > 




Archive powered by MHonArc 2.6.19+.

Top of Page