3

I have a lemma such as the following, with a higher-order parameter:

Require Import Coq.Lists.List.

Lemma map_fst_combine:
  forall A B C (f : A -> C) (xs : list A) (ys : list B),
  length xs = length ys ->
  map (fun p => f (fst p)) (combine xs ys) = map f xs. 
Proof.
  induction xs; intros.
  * destruct ys; try inversion H.
    simpl. auto.
  * destruct ys; try inversion H.
    simpl. rewrite IHxs; auto.
Qed.

I would like to use this as with rewrite. It works if I specify f directly:

Parameter list_fun : forall {A}, list A -> list A.
Parameter length_list_fun : forall A (xs : list A), length (list_fun xs) = length xs.

Lemma this_works:
  forall (xs : list bool),
  map (fun p => negb (negb (fst p))) (combine xs (list_fun xs)) =  xs.
Proof.
  intros.
  rewrite map_fst_combine with (f := fun x => negb (negb x))
    by (symmetry; apply length_list_fun).
Admitted. 

but I would really like not having to do that (in my case, I would like to use this lemma as part of a autorewrite set). But

Lemma this_does_not:
  forall (xs : list bool),
  map (fun p => negb (negb (fst p))) (combine xs (list_fun xs)) =  xs.
Proof.
  intros.
  rewrite map_fst_combine.

fails with

(* 
Error:
Found no subterm matching "map (fun p : ?M928 * ?M929 => ?M931 (fst p))
                             (combine ?M932 ?M933)" in the current goal.
*)

Am I expecting too much here, or is there a way to make this work?

Joachim Breitner
  • 25,395
  • 6
  • 78
  • 139
  • Is it feasible for you to define the composition operator and reformulate your lemmas using it? If you have a lemma `... map (f o fst) (combine xs ys) = map f xs.` you can use it to rewrite `map (negb o negb o fst) (combine xs (list_fun xs)) = xs.`, where `o` is an infix notation for `Definition comp (A B C : Type) (g : B -> C) (f : A -> B) : A -> C := fun x => g (f x).` I should also add that we need `o` to be left associative for that. – Anton Trunov Jun 28 '17 at 14:58
  • In the context of autorewrite, this would require rewriting everything in terms of `o`… not sure if that works well. Or maybe a set of rewrite hints that rewrite `f (fst x)` as `(f o fst) x`, and then also `f o (g o fst)` as `(f o g) o fst`, to bubble the `fst` out? – Joachim Breitner Jun 28 '17 at 15:01

1 Answers1

1

Let's define the composition operator (or you might want to reuse the one defined in Coq.Program.Basics):

Definition comp {A B C} (g : B -> C) (f : A -> B) :=
  fun x : A => g (f x).
Infix "∘" := comp (at level 90, right associativity).

Now, let's formulate the map_fst_combine lemma in terms of composition:

Lemma map_fst_combine:
  forall A B C (f : A -> C) (xs : list A) (ys : list B),
  length xs = length ys ->
  map (f ∘ fst) (combine xs ys) = map f xs.
Admitted.   (* the proof remains the same *)

Now we need some helper lemmas for autorewrite:

Lemma map_comp_lassoc A B C D xs (f : A -> B) (g : B -> C) (h : C -> D) :
  map (fun x => h (g (f x))) xs = map ((h ∘ g) ∘ f) xs.
Proof. reflexivity. Qed.

Lemma map_comp_lassoc' A B C D E xs (f : A -> B) (g : B -> C) (h : C -> D) (i : D -> E) :
  map (i ∘ (fun x => h (g (f x)))) xs = map ((i ∘ h) ∘ (fun x => g (f x))) xs.
Proof. reflexivity. Qed.

With the following hints

Hint Rewrite map_comp_lassoc map_comp_lassoc' map_fst_combine : mapdb.

we are able to do automatic rewrites and get rid of fst and combine:

Lemma autorewrite_works xs :
  map (fun p => negb (negb (fst p))) (combine xs (list_fun xs)) = xs.
Proof.
  autorewrite with mapdb.
  (* 1st subgoal: map (negb ∘ negb) xs = xs *)
Admitted.

Lemma autorewrite_works' xs :
  map (fun p => negb (negb (negb (negb (fst p))))) (combine xs (list_fun xs)) = xs.
Proof.
  autorewrite with mapdb.
  (* 1st subgoal: map (((negb ∘ negb) ∘ negb) ∘ negb) xs = xs *)
Admitted.
Anton Trunov
  • 15,074
  • 2
  • 23
  • 43