0

Will unfold def. fold def. ever achieve anything in a Coq proof?

Put differently: will there ever be a difference between these two sequences of applications of tactics?:

  • unfold def. fold def. cbn.
  • cbn.
Max Heiber
  • 14,346
  • 12
  • 59
  • 97

2 Answers2

2

If you have a look at the documentation for both fold (https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.fold) and unfold (https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.unfold) you can see that they do not expect the same kind of argument. While unfold takes an identifier as argument, fold takes a term.

So if you have def x y in your goal, you can unfold def to access its definition, but then you might have to use fold (def x y) to return to the original goal.

In any case, there is no guarantee that unfold def ; fold (def x y) will result in nothing, since there might other occurrences of the unfolded def x y in the goal.


Here is a concrete example to see fold and unfold in action. If the goal changes after a tactic, I put the new goal in a comment after the tactic. Note also the use of Fail progress tac which asserts that executing tactic tac will not affect the goal at all.

Definition foo (b : bool) :=
  if b then 0 else 1.

Goal foo true + 1 = foo false.
Proof.
  unfold foo.
  (* 0 + 1 = 1 *)
  Fail progress fold foo.
  fold (foo true).
  (* foo true + S (foo true) = S (foo true) *)
  Fail progress fold (foo false).
  unfold foo.
  (* 0 + 1 = 1 *)
  fold (foo false).
  (* 0 + foo false = foo false *)
  fold (foo true).
  (* foo true + foo false = foo false *)
  unfold foo at 2.
  (* foo true + 1 = foo false *)

As you can see, fold foo will not do anything, while fold true and fold false will, of course, it's also greedy, any 0 will turn into fold true.

Théo Winterhalter
  • 4,908
  • 2
  • 18
  • 34
0

Definitely. unfold def inlines the definition of def, and also performs some basic reductions e.g. if def was applied to anything before it got inlined.

Definition hold {T} (x : T) : Prop := True.
Goal (not False -> hold not).
unfold not.
(* inline not: (fun A : Prop => A -> False) False -> hold (fun A : Prop => A -> False)
   and reduce: (False -> False) -> hold (fun A : Prop => A -> False) *)

However, fold def does not "un-reduce" applications of def. If you now do

fold not.

it will not fold False -> False back to not False. It will only find the not under the hold, so you get (False -> False) -> hold not as your goal. (fold (not False) would reduce not False to False -> False, search for that, and then eventually give the goal not False -> hold (fun A : Prop => A -> False, but, again, it hasn't properly undone the unfold). So, basically, the sequence unfold def. fold def. inlines and simplifies usages of def where it has been "used" (e.g. applied), and tries to leave the other usages intact.

Another example, this time with iota-reduction (reducing a destruction) instead of beta-reduction.

Definition def : bool := true.
Definition truth (b : bool) : Prop := if b then True else False.
Goal ((if def then True else False) -> truth def).
unfold def.
(* inline def: (if true then True else False) -> truth true
   and reduce: True -> truth true *)
fold def.
(* goal: True -> truth def *)

In the first case, cbn. and unfold not. fold not. cbn. are different (and in neither case does cbn do anything). In this latter case, cbn. just takes us straight to True -> True no matter where we put it.

HTNW
  • 27,182
  • 1
  • 32
  • 60