Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get list of constructors of Inductive #10095

Closed
samuelgruetter opened this issue Oct 12, 2018 · 3 comments · Fixed by #13920
Closed

Get list of constructors of Inductive #10095

samuelgruetter opened this issue Oct 12, 2018 · 3 comments · Fixed by #13920
Labels
part: ltac2 Issues and PRs related to the (in development) Ltac2 tactic langauge.
Projects
Milestone

Comments

@samuelgruetter
Copy link
Contributor

Is it possible to write the following function in Ltac2 in a generic way, without having to write one line for each type?

Ltac2 constructors_of_type t :=
  match! t with
  | prod _ _ => [ constr:(@pair) ]
  | Z => [ constr:(Z0); constr:(Zpos); constr:(Zneg) ]
  | nat => [ constr:(O); constr:(S) ]
  | _ => Control.throw (Tactic_failure None)
  end.
@JasonGross
Copy link
Member

JasonGross commented Jan 28, 2019

I tried this, but it does not work because of #10094:

Require Import Ltac2.Ltac2.

Module Import Ltac2.
  Module List.
    Ltac2 rec map (f : 'a -> 'b) (ls : 'a list) :=
      match ls with
      | [] => []
      | l :: ls => f l :: map f ls
      end.
    Ltac2 rec fold_right (f : 'a -> 'b -> 'b) (a : 'b) (ls : 'a list) :=
      match ls with
      | [] => a
      | l :: ls => f l (fold_right f a ls)
      end.
  End List.
End Ltac2.

Ltac2 rec head v :=
  match! v with
  | ?f ?x => head f
  | ?x => x
  end.

Ltac2 rec get_constructors_from (i : int) (ind : inductive) :=
  Control.plus
    (fun () => let c := Constr.Unsafe.constructor ind i in
               c :: get_constructors_from (Int.add i 1) ind)
    (fun e
     => match e with
        | Not_found => []
        | _ => Control.throw e
        end).

Ltac2 constructors_of_type t :=
  let t := head t in
  match Constr.Unsafe.kind t with
  | Constr.Unsafe.Ind ind inst
    => let ls := get_constructors_from 0 ind in
         List.map (fun c => Constr.Unsafe.make (Constr.Unsafe.Constructor c inst)) ls
  | _ => Control.throw (Tactic_failure (Some (Message.of_constr t)))
  end.

@JasonGross
Copy link
Member

JasonGross commented Jan 28, 2019

Here is a thing that works. Due to #10090, I decided to use Ltac1's tactics in terms rather than inserting an extra call to hnf. This is very kludgy, and @ppedrot should probably include a primitive that does this, or at least a primitive to count the number of constructors of an inductive. Anyway, here's the code:

Require Import Ltac2.Ltac2.

Module Import Ltac2.
  Module List.
    Ltac2 rec iter (f : 'a -> unit) (ls : 'a list) :=
      match ls with
      | [] => ()
      | l :: ls => f l; iter f ls
      end.
    Ltac2 rec map (f : 'a -> 'b) (ls : 'a list) :=
      match ls with
      | [] => []
      | l :: ls => f l :: map f ls
      end.
    Ltac2 rec fold_right (f : 'a -> 'b -> 'b) (a : 'b) (ls : 'a list) :=
      match ls with
      | [] => a
      | l :: ls => f l (fold_right f a ls)
      end.
    Ltac2 rec seq (start : int) (step : int) (last : int) :=
      match Int.equal (Int.compare (Int.sub last start) step) -1 with
      | true
        => []
      | false
        => start :: seq (Int.add start step) step last
      end.
  End List.
End Ltac2.

Ltac2 get_n_constructors (n : int) (ind : inductive) :=
  List.map (Constr.Unsafe.constructor ind) (List.seq 0 1 n).

Ltac2 count_constructors (ty : constr) :=
  let c := '(fun n : $ty => ltac:(lazymatch goal with n : _ |- _ => destruct n end; exact tt)) in
  match Constr.Unsafe.kind c with
  | Constr.Unsafe.Lambda _ _ c
    => match Constr.Unsafe.kind c with
       | Constr.Unsafe.Case _ _ _ cases
         => Array.length cases
       | _ => Control.throw (Tactic_failure (Some (Message.of_constr c)))
       end
  | _ => Control.throw (Tactic_failure (Some (Message.of_constr c)))
  end.

Ltac2 rec head v :=
  match! v with
  | ?f ?x => head f
  | ?x => x
  end.

Ltac2 constructors_of_type ty :=
  let t := head ty in
  match Constr.Unsafe.kind t with
  | Constr.Unsafe.Ind ind inst
    => let n := count_constructors ty in
       let ls := get_n_constructors n ind in
       List.map (fun c => Constr.Unsafe.make (Constr.Unsafe.Constructor c inst)) ls
  | _ => Control.throw (Tactic_failure (Some (Message.of_constr t)))
  end.

Goal True.
  let ls := List.map constructors_of_type [
                       '(prod nat nat);
                       'nat;
                       '(sum nat nat)
                     ] in
  List.iter (fun v => Message.print (List.fold_right Message.concat (Message.of_string "") (List.map (fun m => Message.concat (Message.of_constr m) (Message.of_string "; ")) v))) ls.
  (* @pair;
0; S;
@inl; @inr;
 *)

@maximedenes maximedenes transferred this issue from coq/ltac2 May 7, 2019
@SkySkimmer SkySkimmer added the part: ltac2 Issues and PRs related to the (in development) Ltac2 tactic langauge. label May 7, 2019
@JasonGross
Copy link
Member

See also #10940

@jfehrle jfehrle added this to Parking lot in Ltac2 Jun 29, 2020
ppedrot added a commit to ppedrot/coq that referenced this issue Mar 10, 2021
Fixes coq#10095: Get list of constructors of Inductive.
ppedrot added a commit to ppedrot/coq that referenced this issue Mar 10, 2021
Fixes coq#10095: Get list of constructors of Inductive.
ppedrot added a commit to ppedrot/coq that referenced this issue Mar 10, 2021
Fixes coq#10095: Get list of constructors of Inductive.
ppedrot added a commit to ppedrot/coq that referenced this issue Mar 10, 2021
Fixes coq#10095: Get list of constructors of Inductive.
ppedrot added a commit to ppedrot/coq that referenced this issue Mar 12, 2021
Fixes coq#10095: Get list of constructors of Inductive.
ppedrot added a commit to ppedrot/coq that referenced this issue Mar 16, 2021
Fixes coq#10095: Get list of constructors of Inductive.
@coqbot-app coqbot-app bot added this to the 8.14+rc1 milestone Mar 16, 2021
@Alizter Alizter moved this from Parking lot to Done in Ltac2 May 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
part: ltac2 Issues and PRs related to the (in development) Ltac2 tactic langauge.
Projects
Ltac2
  
Done
Development

Successfully merging a pull request may close this issue.

3 participants