Skip to Content.
Sympa Menu

coq-club - [Coq-Club] help debugging Extraction Inline with Unset Extraction SafeImplicits

coq-club AT inria.fr

Subject: The Coq mailing list

List archive

[Coq-Club] help debugging Extraction Inline with Unset Extraction SafeImplicits


Chronological Thread 
  • From: Jonathan Leivent <jonikelee AT gmail.com>
  • To: Coq Club <coq-club AT inria.fr>
  • Subject: [Coq-Club] help debugging Extraction Inline with Unset Extraction SafeImplicits
  • Date: Tue, 21 Jun 2016 10:54:23 -0400
  • Authentication-results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=jonikelee AT gmail.com; spf=Pass smtp.mailfrom=jonikelee AT gmail.com; spf=None smtp.helo=postmaster AT mail-qk0-f196.google.com
  • Ironport-phdr: 9a23:+tZY+xEoD3dxr29QXPA6N51GYnF86YWxBRYc798ds5kLTJ75oM6wAkXT6L1XgUPTWs2DsrQf2rKQ6/irAjNIyK3CmU5BWaQEbwUCh8QSkl5oK+++Imq/EsTXaTcnFt9JTl5v8iLzG0FUHMHjew+a+SXqvnYsExnyfTB4Ov7yUtaLyZ/mj6bqo9aIPE1hv3mUX/BbFF2OtwLft80b08NJC50a7V/3mEZOYPlc3mhyJFiezF7W78a0+4N/oWwL46pyv+YJa6jxfrw5QLpEF3xmdjltvIy4/SXEGCCI/zM3Vngc2k5DBBGA5xXnVL/wtDH7v6xzwn/JE9fxSOUWXjKr86diTlfMhSYZOjgluDXVjcpxj69frR+JqBl2woqSa4aQYqktNpjBdM8XEDISFv1aUDZMV8blN9MC

Does anyone have experience debugging Extraction Inline failures with Unset Extraction SafeImplicits? I just tried this for the first time, and am not understanding what went wrong based on the comment placed in the output by Unset Extraction SafeImplicits. The warning is:

Warning:
At least an implicit occurs after extraction : 3rd argument (a) of wfi_lt.
Extraction SafeImplicits is unset, extracting nonetheless,
but this code is potentially unsafe, please review it manually.

The Coq script is attached. The key extracted function is:

let merge_sort d ls =
let rec f _ =
let iH = fun y -> f y in
(fun d0 ls0 _ ->
let (ls1, ls2) = split ls0 in
(match ls2 with
| [] -> ls1
| _ :: _ -> merge_acc d0 (iH (length ls1) (not d0) ls1 __) (iH (length ls2) (not d0) ls2 __) []))
in f __ (* 3rd argument (a) of wfi_lt *) d ls __
end

It looks to me like the first arg of f is understood as not used by extraction. So, what is the comment saying about that arg?

The function wfi_lt (well-founded induction using lt) was defined with:


Definition wfi_lt := well_founded_induction_type Wf_nat.lt_wf.

Extraction Implicit wfi_lt [1 3].

Extraction Inline wfi_lt.


Interestingly, merge_acc also uses wfi_lt, but extraction had no difficulty with it:


let rec merge_acc d ls1 ls2 acc =
match ls1 with
| [] ->
(match ls2 with
| [] -> acc
| b :: ls4 -> merge_acc d [] ls4 (b :: acc))
| a :: ls3 ->
(match ls2 with
| [] -> merge_acc d [] ls3 (a :: acc)
| b :: ls4 -> if le_or_ge_dec d a b then merge_acc d ls1 ls4 (b :: acc) else merge_acc d ls3 ls2 (a :: acc))


This is using 8.5pl1

Thanks,

-- Jonathan


Require Import Coq.Lists.List.
Import ListNotations.
Require Import Omega.
Require Import Coq.Classes.RelationClasses.

Ltac revert_all :=
  repeat lazymatch goal with H :_ |- _ => revert H end.

Ltac intro_to hyp :=
  intro;
  lazymatch goal with
  | H :_ |- _ => tryif constr_eq H hyp then idtac else intro_to hyp
  end.

Definition wfi_lt := well_founded_induction_type Wf_nat.lt_wf.

Tactic Notation "wfinduction" constr(term) "as" ident(H) :=
  let R := fresh in
  let E := fresh in
  remember term as R eqn:E;
  move R at top; revert E; revert_all;
  induction R as [R H] using wfi_lt;
  intro_to E; subst R.

Ltac wfisolve := rewrite ?app_length in *; cbn in *; omega.

Lemma app_cons_rw : forall {T} ls1 (a : T) ls2, ls1 ++ a :: ls2 = (ls1 ++ [a]) ++ ls2.
Proof.
  intros. rewrite <-app_assoc. cbn. reflexivity.
Qed.

(*A fully-dependently-typed merge sort, starting from scratch.*)
Module MergeSort.
  Parameter A : Type.
  Parameter eq_dec : forall (a b : A), {a = b} + {a <> b}.
  Parameter le : A -> A -> Prop.
  Parameter le_ge_dec : forall (a b : A), {le a b} + {le b a}.
  Context (le_pre : PreOrder le).
  Context (le_po : PartialOrder eq le).

  Notation "x =! y" := (eq_dec x y) (at level 70, no associativity).

  Fixpoint count (x : A)(ls : list A) : nat :=
    match ls with
    | [] => 0
    | a :: ls' => (if (a =! x) then 1 else 0) + count x ls'
    end.

  Lemma count_app : forall x ls1 ls2, count x (ls1 ++ ls2) = count x ls1 + count x ls2.
  Proof.
    induction ls1. all:cbn. all:intros. 1:reflexivity.
    specialize (IHls1 ls2). omega.
  Qed.

  Lemma count_length : forall x ls, count x ls <= length ls.
  Proof.
    induction ls as [|a ls]. all:cbn. 1:omega. 
    destruct (a =! x). all:omega.
  Qed.

  Notation mem x ls := (count x ls > 0).

  Definition permut ls1 ls2 := (forall x, count x ls1 = count x ls2).

  Lemma permut_transitive : Transitive permut.
  Proof.
    intros ls1 ls2 ls3 H1 H2.
    unfold permut in *.
    intro x.
    specialize (H1 x).
    specialize (H2 x).
    congruence.
  Qed.

  Instance permut_equivalence : Equivalence permut.
  Proof.
    split. 3:apply permut_transitive.
    all:simpl_relation.
  Qed.

  (*Not a fully specified remove function, but sufficient for its use here:*)
  Local Definition remove1 a ls :
    mem a ls -> { rls | length ls = S (length rls) /\ permut ls (a::rls) }.
  Proof.
    induction ls as [|b ls IHls]. all:cbn. all:intro H. 1:omega.
    case (a =! b); intros.
    - subst b. exists ls. split. all:reflexivity.
    - edestruct IHls as [rls (H1 & H2)].
      { destruct (b =! a). 1:congruence. omega. }
      exists (b::rls). unfold permut in *. cbn. split. 1:omega.
      intro x. destruct (a =! x).
      + subst x. destruct (b =! a). 1:congruence.
        pose proof (H2 a). cbn in *. destruct (a =! a). 1:omega. congruence.
      + pose proof (H2 x). cbn in *. destruct (a =! x). 1:congruence. omega.
  Qed.

  Lemma permut_length ls1 ls2 : permut ls1 ls2 -> length ls1 = length ls2.
  Proof.
    unfold permut.
    wfinduction (length (ls1++ls2)) as IH.
    destruct ls1 as [|a ls1]. all:cbn. all:intro H.
    - destruct ls2 as [|b ls2]. 1:reflexivity.
      specialize (H b). cbn in H. destruct (b =! b). 1:omega. congruence.
    - pose proof (H a) as Ha. destruct (a =! a) as [_|?]. 2:congruence.
      edestruct (remove1 a ls2) as (ls2a & H1 & H2). 1:omega.
      rewrite H1. f_equal.
      unshelve eapply (IH _ _ ls1 ls2a eq_refl). 1:wfisolve.
      intro x. pose proof (H x) as Hx. pose proof (H2 x) as Hx2.
      all:cbn in *. destruct (a =! x). all:subst. all:omega.
  Qed.

  Lemma permut_app : forall ls1 ls2 ls3 ls4, permut ls1 ls3 -> permut ls2 ls4 -> permut (ls1 ++ ls2) (ls3 ++ ls4).
  Proof.
    intros ls1 ls2 ls3 ls4 H1 H2.
    intro x. specialize (H1 x). specialize (H2 x).
    rewrite ?count_app. omega.
  Qed.

  Definition le_or_ge (direction : bool)(a b : A) := if direction then le a b else le b a.

  Notation "a <=[ d ]>= b" := (le_or_ge d a b) (at level 70, no associativity,
                                               format "a  <=[ d ]>=  b").

  Definition le_or_ge_dec d a b : {a<=[d]>=b}+{b<=[d]>=a}.
  Proof.
    destruct d. all:cbn.
    - apply le_ge_dec.
    - apply le_ge_dec.
  Qed.

  Lemma le_or_ge_transitive : forall d, Transitive (le_or_ge d).
  Proof.
    intros (). all:cbv. all:intros x y z H1 H2. all:etransitivity. all:eassumption.
  Qed.

  Instance le_or_ge_preorder d : PreOrder (le_or_ge d).
  Proof.
    split. 2:apply le_or_ge_transitive. destruct d. all:simpl_relation.
  Qed.

  Instance le_or_ge_partial_order d : PartialOrder eq (le_or_ge d).
  Proof.
    pose proof (partial_order_antisym le_po) as POA.
    destruct d. all:cbv. all:intros a b.
    all:destruct (eq_dec a b). all:simpl_relation.
  Qed.

  (*directional sorting:*)
  Definition dsorted d (ls : list A) := forall ls1 x ls2 y ls3, ls = ls1 ++ x::ls2 ++ y::ls3 -> x<=[d]>=y.

  Lemma dsorted_le d : forall ls1 x ls2 y ls3, dsorted d (ls1 ++ x::ls2 ++ y::ls3) -> x<=[d]>=y.
  Proof.
    intros * H. eapply H. reflexivity.
  Qed.

  Lemma dsorted_nil d : dsorted d [].
  Proof.
    intros ? * ?%app_cons_not_nil. contradiction.
  Qed.

  Lemma dsorted_single d : forall n, dsorted d [n].
  Proof.
    intros ? () * [= -> ?%app_cons_not_nil]. all:contradiction.
  Qed.

  Lemma dsorted_tail d : forall a ls, dsorted d (a :: ls) -> dsorted d ls.
  Proof.
    intros * H. unfold dsorted. intros * ->. apply (H (_::_) _ _ _ _ eq_refl).
  Qed.

  Lemma dsorted_head d : forall a b ls, dsorted d (a::b::ls) -> a<=[d]>=b.
  Proof.
    intros * H. apply (H [] _ [] _ _ eq_refl).
  Qed.

  Lemma dsorted_cons d : forall a b ls, dsorted d (b::ls) -> a<=[d]>=b -> dsorted d (a::b::ls).
  Proof.
    intros * H1 H2. unfold dsorted. intros () ? ls2 ? ? [= -> H].
    - revert H. destruct ls2. all:intros [= -> ->]. 1:assumption.
      etransitivity. 1:eassumption. apply (H1 [] _ _ _ _ eq_refl).
    - rewrite H in H1. apply (H1 _ _ _ _ _ eq_refl).
  Qed.

  Hint Rewrite @app_comm_cons @app_assoc : assoc_rws.

  Lemma dsorted_app d : forall ls1 ls2, dsorted d (ls1 ++ ls2) -> dsorted d ls1 /\ dsorted d ls2.
  Proof.
    intros * H. split. all:intros ? * -> .
    1:eapply (H _ _ _ _ (_ ++ _)). 2:eapply (H (_ ++ _) _ _ _ _).
    all:autorewrite with assoc_rws. all:reflexivity.
  Qed.

  Lemma dsorted_splice d : forall ls1 a ls2 b ls3,
      dsorted d (ls1 ++ a::ls2) -> dsorted d (ls2 ++ b::ls3) -> a<=[d]>=b -> dsorted d (ls1 ++ a::ls2 ++ b::ls3).
  Proof.
    induction ls1.
    - intros ? () **. all:cbn in *.
      + apply dsorted_cons. all:assumption.
      + apply dsorted_cons. 1:assumption.
        eapply dsorted_head. eassumption.
    - intros. destruct ls1. all:cbn in *.
      + apply dsorted_cons.
        * apply IHls1. 1:eapply dsorted_tail. all:eassumption.
        * eapply dsorted_head. eassumption.
      + apply dsorted_cons.
        * apply IHls1. 1:eapply dsorted_tail. all:eassumption.
        * eapply dsorted_head. eassumption.
  Qed.

  Lemma dsorted_flip d : forall ls, dsorted d ls <-> dsorted (negb d) (rev ls).
  Proof.
    induction ls. all:cbn [rev]. all:split. all:intro H.
    - apply dsorted_nil.
    - apply dsorted_nil.
    - destruct ls. 1:apply dsorted_single.
      apply dsorted_head in H as H1.
      apply dsorted_tail in H as H2.
      apply dsorted_tail in H2 as H3.
      cbn [rev]. rewrite <-app_assoc. eapply dsorted_splice.
      + apply IHls. assumption.
      + apply dsorted_single.
      + destruct d. all:assumption.
    - destruct ls. 1:apply dsorted_single.
      cbn [rev] in H.
      destruct (dsorted_app _ _ _ H) as [H1 _].
      rewrite <-app_assoc in H.
      apply dsorted_le in H as H2.
      apply <-IHls in H1.
      apply dsorted_cons. 2:destruct d. all:assumption.
  Qed.

  Definition split_acc (ls : list A) : forall acc1 acc2,
      (length acc1 = length acc2 \/ length acc1 = S (length acc2)) ->
      { lss | (length (fst lss) = length (snd lss) \/ length (fst lss) = S (length (snd lss)))
              /\ permut (ls ++ acc1 ++ acc2) (fst lss ++ snd lss) }.
  Proof.
    induction ls as [|a ls IHls]. all:intros acc1 acc2 H.
    { exists (acc1, acc2). cbn. split. 1:assumption. reflexivity. }
    destruct (IHls (a::acc2) acc1) as [[ls1 ls2] (H1 & H2)].
    { cbn. omega. }
    cbn [fst snd] in *.
    exists (ls1, ls2). cbn. split. 1:assumption.
    intro x. specialize (H2 x).
    autorewrite with assoc_rws in *. rewrite ?count_app in *. cbn in *. omega.
  Qed.

  Definition split (ls : list A) :
    { lss | (length (fst lss) = length (snd lss) \/ length (fst lss) = S (length (snd lss)))
            /\ permut ls (fst lss ++ snd lss) }.
  Proof.
    destruct (split_acc ls [] []) as [lss (H1 & H2)]. 1:omega.
    exists lss. split. 1:omega.
    intro x. specialize (H2 x). rewrite ?count_app in *. cbn in *. omega.
  Qed.

  Definition merge_acc d (ls1 ls2 acc : list A) :
    { ls | (dsorted (negb d) ((rev acc) ++ ls1) -> dsorted (negb d) ((rev acc) ++ ls2) -> dsorted d ls)
           /\ permut ls (ls1 ++ ls2 ++ acc) }.
  Proof.
    wfinduction (length (ls1 ++ ls2)) as IH.
    destruct (ls1) as [|a ls3] eqn:Els1, (ls2) as [|b ls4] eqn:Els2.
    - exists acc. cbn. rewrite app_nil_r. split. 2:reflexivity.
      intros. rewrite dsorted_flip. assumption.
    - unshelve eelim (IH _ _ d [] ls4 (b::acc) eq_refl). 1:wfisolve.
      intros ls (H1 & H2).
      exists ls. cbn -[count] in *. split.
      + intros H3 H4. rewrite app_nil_r in *.
        rewrite app_cons_rw in H4. destruct (dsorted_app _ _ _ H4) as (H5 & _).
        apply H1. all:assumption.
      + intro x. specialize (H2 x). rewrite app_comm_cons. rewrite count_app in *. cbn [count] in *. omega.
    - unshelve eelim (IH _ _ d [] ls3 (a::acc) eq_refl). 1:wfisolve.
      intros ls (H1 & H2).
      exists ls. cbn -[count] in *. split.
      + intros H3 H4. rewrite app_nil_r in *.
        rewrite app_cons_rw in H3. destruct (dsorted_app _ _ _ H3) as (H5 & _).
        apply H1. all:assumption.
      + intro x. specialize (H2 x). rewrite app_comm_cons. rewrite count_app in *. cbn [count] in *. omega.
    - case (le_or_ge_dec d a b). all:intro C.
      + unshelve eelim (IH _ _ d ls1 ls4 (b::acc) eq_refl). all:subst. 1:wfisolve.
        intros ls (H1 & H2).
        exists ls. cbn -[count] in *. split.
        * intros H3 H4. apply H1.
          -- rewrite <-app_assoc. eapply dsorted_splice.
             ++ rewrite app_cons_rw in H4. apply dsorted_app in H4. tauto.
             ++ apply dsorted_app in H3. tauto.
             ++ destruct d. all:assumption.
          -- rewrite <-app_assoc. cbn. assumption.
        * intro x. specialize (H2 x). autorewrite with assoc_rws in *. rewrite ?count_app in *.
          cbn [count] in *. omega.
      + unshelve eelim (IH _ _ d ls3 ls2 (a::acc) eq_refl). all:subst. 1:wfisolve.
        intros ls (H1 & H2).
        exists ls. cbn -[count] in *. split.
        * intros H3 H4. apply H1.
          -- rewrite <-app_assoc. cbn. assumption.
          -- rewrite <-app_assoc.  eapply dsorted_splice.
             ++ rewrite app_cons_rw in H3. apply dsorted_app in H3. tauto.
             ++ apply dsorted_app in H4. tauto.
             ++ destruct d. all:assumption.
        * intro x. specialize (H2 x). autorewrite with assoc_rws in *. rewrite ?count_app in *.
          cbn [count] in *. omega.
  Qed.

  Definition merge_sort d ls : { rls | dsorted d rls /\ permut ls rls }.
  Proof.
    wfinduction (length ls) as IH.
    case (split ls).
    intros (ls1 & ls2) (H1 & H2).
    cbn [fst snd] in *.
    destruct (ls2) as [|a ls3] eqn:els2.
    - exists ls1. cbn in *. destruct H1.
      + apply length_zero_iff_nil in H. subst. split.
        * apply dsorted_nil.
        * intro x. specialize (H2 x). cbn in *. assumption.
      + destruct ls1 as [|a ls1].
        * cbn in H. discriminate.
        * cbn in *. injection H. clear H. intro H. apply length_zero_iff_nil in H. subst. split.
          -- apply dsorted_single.
          -- intro x. specialize (H2 x). cbn in *. assumption.
    - apply permut_length in H2 as H2'.
      unshelve eelim (IH _ _ (negb d) ls1 eq_refl). 1:wfisolve.
      intros rls1 (H3 & H4).
      unshelve eelim (IH _ _ (negb d) ls2 eq_refl). all:subst. 1:wfisolve.
      intros rls2 (H5 & H6).
      elim (merge_acc d rls1 rls2 []).
      intros rls (H7 & H8).
      cbn [rev app] in H7. rewrite ?app_nil_r in H8.
      exists rls. split.
      + apply H7. all:assumption.
      + etransitivity. 1:eassumption.
        etransitivity. 2:symmetry. 1:apply permut_app. all:eassumption.
  Qed.

End MergeSort.
Import MergeSort.

Require Import ExtrOcamlNatInt.
Extraction Inline le_ge_dec.
Extract Inlined Constant eq_dec => "(=)".
Extract Inlined Constant le_ge_dec => "(<=)".
Extract Inlined Constant length => "length".
Extract Inlined Constant negb => "not".
Extract Inlined Constant app => "append".
Print wfi_lt.
Extraction Implicit wfi_lt [1 3].
Extraction Inline wfi_lt.
Unset Extraction SafeImplicits.
Recursive Extraction MergeSort.



Archive powered by MHonArc 2.6.18.

Top of Page