Example:
Goal ∀ type (anEqDecision: EqDecision type) (aCountable: Countable type) (x: type)
, decode (encode x) = Some x.
intros. destruct aCountable.
(*
type : Type
anEqDecision : EqDecision type
encode : type → positive
decode : positive → option type
decode_encode : ∀ x : type, decode (encode x) = Some x
x : type
============================
countable.decode (countable.encode x) = Some x
*)
rewrite (decode_encode x).
(*
Error: Found no subterm matching "decode (encode x)" in the current goal.
*)
If I rewrite the other way, I can use reflexivity:
Goal ∀ type (anEqDecision: EqDecision type) (aCountable: Countable type) (x: type)
, decode (encode x) = Some x.
intros. destruct aCountable.
rewrite <- (decode_encode x).
(*
type : Type
anEqDecision : EqDecision type
encode : type → positive
decode : positive → option type
decode_encode : ∀ x : type, decode (encode x) = Some x
x : type
============================
countable.decode (countable.encode x) = decode (encode x)
*)
reflexivity. Qed.
So, apparently Coq knows that countable.decode
= decode
and countable.encode
= encode
? What is going on here? How can I rewrite it the way I want?
Try simplifying the goal before rewriting (cbn
, maybe after unfold countable.decode
if it does nothing). Rewriting pretty much requires expressions to match exactly, whereas reflexivity
reduces the two sides so it can equate more terms.
Thanks! unfold countable.decode, countable.encode.
converts it into decode
and encode
! Why does it though?
Why are they introduced like that in the first place?
I notice that decode
and encode
in the goal only become countable.decode
and countable.encode
after I destruct aCountable
.
Only for me to unfold them back. Coq is trying to make my life harder for no reason?
Before you destruct, countable.encode
can be shortened to encode
, but after that would refer to the local context so a more precise name is printed
Do Set Printing All
before and after your destruct and reduction to see what happens
Oh, I see. Before destruct aCountable.
, it is @decode type anEqDecision aCountable
, so it refers to aCountable
. After destruct aCountable.
, there is no more aCountable.
so it becomes complicated.
It even inlines the class dictionary.
I think this problem would disappear if you avoid destructing the typeclass instance; I don't think stdpp (or its main client Iris) ever do that.
Then how do I get the proof that decode
retracts encode
from out of said instance?
decode_encode
Thanks!
Last updated: Sep 23 2023 at 14:01 UTC