0

I have the following code:

    assume H: "x ≠ xa ∧ x ∈ elems xs" (is "?H1 ∧ ?H2")
    hence "?H1" and "?H2" by auto
    from Cons.IH[OF `?H2` ] have 1: "∃ys zs. xs = ys @ x # zs ∧ x ∉ elems ys" by simp
    then obtain ys zs where 2: "xs = ys @ x # zs ∧ x ∉ elems ys" (is "?C1 ∧ ?C2") by blast
    hence "?C1" and "?C2" by auto
    from `?C1` have R1: "xa # xs = (xa # ys) @ x # zs" by simp
    from `x ≠ xa` and `x ∉ elems ys` have R2: "x ∉ elems (xa#ys)" by auto
    from R1 R2 show ?case by blast

Without the lines : hence "?H1" and "?H2" by auto and hence "?C1" and "?C2" by auto I cannot refer to the literal facts `?C1` and `?H2`. (I also cannot refer to the terms the "unkowns/abbreviations/metavariables/" ?<name> expand to; I get the same error. The metavariables are actually expanded to the literal facts they refer to in the error message (e.g. for `?H2` I get

Failed to retrieve literal fact⌂:
x ∈ elems xs

, so they must be in scope somehow??)

My question is:

  • Why does this not work?
  • is there a better workaround than my hence … by auto?
cxandru
  • 158
  • 8
  • 2
    Using `(is "?H1 ∧ ?H2")` does not automatically turn `?H1` and `?H2` into literal facts, since you haven't yet derived the individual facts `?H1` and `?H2` by applying, for example, the rules `conjunct1` and `conjunct2` (actually, the only literal fact you can refer to at that point is `?H1 ∧ ?H2`). You could, of course, refer to `?H1` and `?H2` individually in other contexts, e.g., `let ?f = "?H1"`. As for the second part of your question, I'm not aware of a better workaround. – Javier Díaz Feb 06 '23 at 23:15

1 Answers1

1

Expanding on Javier's comment, the (is "?H1 ∧ ?H2") creates two macro variables. Those are in scope, such as is ?case for instance. ?H1 and ?H2 refer to the terms x ≠ xa and x ∈ elems xs, but this does not mean that they are proven facts. What changes, are the term bindings, as you can inspect by:

assume H: "x ≠ xa ∧ x ∈ elems xs" (is "?H1 ∧ ?H2")
print_term_bindings
>>>>
?H1 ≡ ¬ x = xa
?H2 ≡ x ∈ elems xs
...

print_facts
>>>>
H: x ≠ xa ∧ x ∈ elems xs
...

Your snippet is just a sugared way of writing:

assume H: "x ≠ xa ∧ x ∈ elems xs"
hence "x ≠ xa" and "x ∈ elems xs" by auto
from Cons.IH[OF `x ∈ elems xs`] have 1: "∃ys zs. xs = ys @ x # zs ∧ x ∉ elems ys" by simp
then obtain ys zs where 2: "xs = ys @ x # zs ∧ x ∉ elems ys" by blast
hence "xs = ys @ x # zs" and "x ∉ elems ys" by auto
from `xs = ys @ x # zs` have R1: "xa # xs = (xa # ys) @ x # zs" by simp
from `x ≠ xa` and `x ∉ elems ys` have R2: "x ∉ elems (xa#ys)" by auto
from R1 R2 show [whatever ?case expands to] by blast

Clearly, this proof does not work if you drop the line hence "x ≠ xa" and "x ∈ elems xs" by auto, which proves the literal fact x ∈ elems xs. Without it, Isabelle cannot accept Cons.IH[OF `x ∈ elems xs`], which causes the error you cite.

Regarding the question of how to write an equivalent proof without the need for hence … by auto: You can't, really. There needs to be some proof that the conjuncts are facts.

The most lightweight way to refer to sub-conjuncts of facts as facts is with conjunct1/2[OF ...]: Just write from Cons.IH[OF conjunct2[OF H]] have... instead of from Cons.IH[OF `?H2`] have....

However, what you are emulating here through term bindings is actually the “array” feature of Isabelle's facts.

If one writes a fact as a chain of sub-facts H: ‹x ≠ xa› ‹x ∈ elems xs› instead of H: ‹x ≠ xa ∧ x ∈ elems xs›, one can afterwards refer to the first part as H(1) and to the second one as H(2). In your example, one would have to slightly adapt the surrounding proof (using safe or clarify) in order for the changed assumption to be okay. It would then read something like:

proof (..., safe)
  assume H: "x ≠ xa" "x ∈ elems xs"
  from Cons.IH[OF H(2)] have 1: "∃ys zs. xs = ys @ x # zs ∧ x ∉ elems ys" by simp
  then obtain ys zs where C: "xs = ys @ x # zs" "x ∉ elems ys" by blast
  from C(1) have R1: "xa # xs = (xa # ys) @ x # zs" by simp
  from `x ≠ xa` and `x ∉ elems ys` have R2: "x ∉ elems (xa#ys)" by auto
  from R1 R2 show ?case by blast
next ...

No macros for literal-fact names or unpacking needed!

My general experience is that there are very limited reasons to use the macros for naming literal facts when you can use the conventional naming of facts. Even more generally, most of the time when one can express a conjunction or an implication at the meta level, opting for meta will make life easier: assumes P: "a" "b" shows "c" is more handy than shows "a /\ b ==> c".

Ben Keks
  • 671
  • 4
  • 11
  • Of course, the solution is trivial if you start with the assumption `H: ‹x ≠ xa› ‹x ∈ elems xs›`, which is comprised by _two_ literal facts, instead of `H: ‹x ≠ xa ∧ x ∈ elems xs›`. Therefore, I think the accepted answer does not actually answer the second part of the question. – Javier Díaz Feb 07 '23 at 12:51
  • @JavierDíaz you're right, but it does work in the second case. I can leave the question open a bit longer in case someone knows a workaround that works for both cases – cxandru Feb 07 '23 at 14:35
  • @cxandru: I don't see how it can work in the second case when the "solution" starts with two literal facts instead of one. That is, how can you derive both `P` and `Q` from `P ∧ Q` _directly_? As I understood it, your question includes the assumption that you start with a fact of the form `P ∧ Q`, not with the _two_ facts `P` and `Q` separately; otherwise the question does not make much sense. – Javier Díaz Feb 07 '23 at 18:12
  • One can virtually always phrase the surrounding goals and proofs in such a way that one can assume the conjunction on the meta level. (And the proof will usually be clearer and shorter.) If you really can't, then doing away with the macro variables would still be the better way to go: `assume ‹x ≠ xa ∧ x ∈ elems xs› hence H: ‹x ≠ xa› ‹x ∈ elems xs› by blast ` – Ben Keks Feb 07 '23 at 19:25
  • Again: the original question states that one starts with a _single-fact_ assumption `"x ≠ xa ∧ x ∈ elems xs"`. The question, as I understand it, asks (1) why one cannot directly refer to the individual components of this conjunction as literal facts (which, I think, is already clear), and (2) whether there is a better way to refer to the individual components as literal facts _without deriving them first_ (which, as I mentioned, is not possible AFAIK). If you start with the _different assumptions_ `"x ≠ xa"` and `"x ∈ elems xs"` then it's obviously possible to refer to them individually. – Javier Díaz Feb 07 '23 at 21:16
  • Yeah, but that's the answer: If you don't want to unpack conjuncts from object logic, write your proofs in such a way that top-level conjunction is handled in the meta logic. – Ben Keks Feb 08 '23 at 13:00
  • I don't agree that's the answer to the original question, but if the question's author is satisfied then I'm happy. – Javier Díaz Feb 08 '23 at 13:27