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: Tej Chajed <tchajed AT mit.edu>
  • To: coq-club <coq-club AT inria.fr>
  • Subject: Re: [Coq-Club] help calling ltac1 function from ltac2
  • Date: Sat, 15 Aug 2020 21:39:11 -0500
  • Authentication-results: mail3-smtp-sop.national.inria.fr; spf=None smtp.pra=tchajed AT mit.edu; spf=Pass smtp.mailfrom=tchajed AT mit.edu; spf=None smtp.helo=postmaster AT outgoing.mit.edu
  • Ironport-phdr: 9a23:7KsPGhEulNpW4dlgpWXjDp1GYnF86YWxBRYc798ds5kLTJ7zpcWwAkXT6L1XgUPTWs2DsrQY0rSQ6vi4EjJZqb+681k6OKRWUBEEjchE1ycBO+WiTXPBEfjxciYhF95DXlI2t1uyMExSBdqsLwaK+i764jEdAAjwOhRoLerpBIHSk9631+ev8JHPfglEnjWwba5zIRmssAndqtUajYRjJ6os1xDEvmZGd+NKyG1yOFmdhQz85sC+/J5i9yRfpfcs/NNeXKv5Yqo1U6VWACwpPG4p6sLrswLDTRaU6XsHTmoWiBtIDBPb4xz8Q5z8rzH1tut52CmdIM32UbU5Uims4qt3VBPljjoMOjgk+2/Vl8NwlrpWrx2vpxN9w4DaboKbOudgcKzBZt4VX3ZNU9xLWiBdHo+xbY0CBPcBM+ZCqIn9okMDowWgCgmuGeji1D9IiWX03aIkzusqDAbL3BA8ENIOqnvUrsv6O7oJXOCwzanI0S/PYO1L1jfg8YXFdA0qrv6QU7xqa8XR1VUvGB3fjlWWsYHrMDeY2+cCvWWa4ORsSOaihnMnpg1toDWix9khh4vViowa1F3J9iF0zZgoKdC2SUN3fMCoHZtMui+VNYZ4TMEvTmd1syg0zb0GvIS0fCkMyJk/yB7fbuaIc4mM4h75SOmRJjJ4iGpleLO/nxay6lKsyu37Vsi61ltBsylLksHUu3wQ1BHf8MyKRuFj8kqiwzqDyh3f5vlaLUwokafXMZ0sz74qmpYNrEjOGjX6lUrogKKQa04q4PKn6/79bbXjvpKcN5F7igX5Mqk2ncy/HPg4MgcJX2ia/+S826fv/Uj4QLVWlPE5jLTWsI3CKcQaoK62HRNV354+5xu8FTur1M4UkWcEIV5fZR6LkpDlO1TUL/D5Cfe/jU6skDBux/3eIr3uHpXNIWLBkLj/YLlw8EtcyAsvzdxF+Z1bF6wBLOrpWkDtrNzYEgM5Mwuszun7D9V9z5oSVn6LAq+EK6zfqkSI5+IqI+mUfoAZojf9K/4/5/7vl3A1g1EdfbP6lacQPXu/B7FtJ1iTKS7nhc5EGmMXtCI/SvbrgRuMS2gASWy1WvcA6zNzI4KvD4rPDtSxi7yI3iq3NphXeiZLBk3aQiSgTJmNR/pZMHHaGcRmiDFRDeH9Gb9k7gmnsUrB85QiNvDdq38dtI6l2dRotbWKxEMCsAdsBsHY6FmjCmR9n2cGXTgzjfJ6oFA7x1ueg/Eh3q5oUOdL7vYMaT8UcJ7Ry+sjW4L1Rx7OedaPRxCjQ8ngDD0sHIo8

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

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 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