Zulip Chat Archive

Stream: general

Topic: differences in elaboration


Gihan Marasingha (Jul 19 2021 at 14:37):

If I copy out the definition of nat.no_confusion and call it nat.no_confusion', as below, Lean has no problems with the line nat.no_confusion' h in the proof of one_ne_two. But if I use nat.no_confusion itself, I need to write @nat.no_confusion _ _ _ h instead.

Two questions:

  1. Why is there this difference in behaviour? That is, how does nat.no_confusion differ from nat.no_confusion'?
  2. Why does @nat.no_confusion _ _ _ hwork when nat.no_confusion hdoesn't? The former expression seems to provide no more information than the latter.
universe l

@[reducible]
protected def nat.no_confusion' : Π {P : Sort l} {v1 v2 : }, v1 = v2  nat.no_confusion_type P v1 v2 :=
λ {P : Sort l} {v1 v2 : } (h12 : v1 = v2),
  @eq.rec  v1 (λ (a : ), v1 = a  nat.no_confusion_type P v1 a)
    (λ (h11 : v1 = v1),
       @nat.cases_on (λ {v1 : }, nat.no_confusion_type P v1 v1) v1 (λ (a : P), a)
         (λ (n : ) (a : n = n  P), a (@eq.refl  n))) v2 h12 h12

open nat

lemma zero_ne_one : 0  1 := λ h, nat.no_confusion' h

lemma one_ne_two : succ 0  succ (succ 0) :=
λ (h : succ 0 = succ(succ 0)),
have h₂ : (0 = succ 0  false)  false, from
  nat.no_confusion' h,
h₂ zero_ne_one

Eric Wieser (Jul 19 2021 at 14:53):

The difference is that nat.no_confusion has @[elab_as_eliminator]

Eric Rodriguez (Jul 19 2021 at 15:02):

Is there any easy way to see what attributes there is? Maybe a #print attribute?

Mario Carneiro (Jul 19 2021 at 15:02):

regular #print will show you all the attributes on a definition

Alex J. Best (Jul 19 2021 at 15:02):

The elaborator works differently for "official" no_confusion applications https://github.com/leanprover-community/lean/blob/65ad4ffdb3abac75be748554e3cbe990fb1c6500/src/frontends/lean/elaborator.cpp#L1814 as you've made a new declaration by hand it doesnt satisfy is_no_confusion and so is not treated specially by the elaborator.

Eric Wieser (Jul 19 2021 at 15:04):

(id @nat.no_confusion) works too in place of nat.no_confusion'

Mario Carneiro (Jul 19 2021 at 15:08):

note that in the error message, the type that it thinks nat.no_confusion h ought to have:

nat.no_confusion_type ((0 = 1  false)  false) 1 1.succ

unfolds to

(0 = 1  (0 = 1  false)  false)  (0 = 1  false)  false

Mario Carneiro (Jul 19 2021 at 15:09):

that is, it is using the entire goal as the major premise, rather than just the right hand side of the implication

Mario Carneiro (Jul 19 2021 at 15:11):

this is the proof it was expecting you to write:

lemma one_ne_two : succ 0  succ (succ 0) :=
λ (h : succ 0 = succ(succ 0)),
  nat.no_confusion h $ λ h, nat.no_confusion h

Gihan Marasingha (Jul 19 2021 at 16:20):

Thanks all. It seems (unless I'm wildly mistaken [EDIT: I am wildly mistaken!]) that @Eric Wieser's answer is related to the answers to the question I asked yesterday about the use of id in generated proofs.

I don't yet understand enough about elaboration / type-checking to see why id helps the kernel in inferring the correct type. Does its use here prevent the special elaboration of no_confusion function applications mentioned by @Alex J. Best ?

Mario Carneiro (Jul 19 2021 at 16:22):

no, id is helping the kernel, after elaboration is complete. This no_confusion stuff is about how elaboration works, before we know all details of the given expression and are trying to fill metavariables

Mario Carneiro (Jul 19 2021 at 16:23):

the reason having id helps the kernel is because checking id B (id C e) : A entails proving that A is defeq to B and B is defeq to C and the type of e is defeq to C, while checking e : A means checking that the type of e is defeq to C

Gihan Marasingha (Jul 19 2021 at 16:23):

Thanks @Mario Carneiro. So would it be fair to say that I was wildly mistaken in my previous comment?

Mario Carneiro (Jul 19 2021 at 16:25):

obviously the first thing implies the second if you assume defeq is transitive, but it's not, and more to the point, there can be a large runtime cost difference between checking the former and the latter, even if the kernel can ultimately find its way to the end

Mario Carneiro (Jul 19 2021 at 16:26):

it's the same idea as giving a proof in small steps vs giving no hints and letting the reader come up with their own proof

Mario Carneiro (Jul 19 2021 at 16:29):

That said, most uses of id in tactics are superfluous. The reason they show up so often is because the primitive that does change inserts that identity term, in order to avoid the rare pathologies where dropping the id causes problems

Yakov Pechersky (Jul 19 2021 at 16:29):

Specifically, this part: image.png

Gihan Marasingha (Jul 19 2021 at 16:42):

I think I understand now. Just to make sure I'm not being an idiot, @Mario Carneiro, are those meant to be @ids in your example? If so, I see that the use of @id provides type information.

I also see that the answers to many of the questions I ask are found in your thesis, so I really should get round to reading it!

Mario Carneiro (Jul 19 2021 at 16:42):

yes those are @id

Mario Carneiro (Jul 19 2021 at 16:43):

by the way, show T, from e is syntactic sugar for @id T e

Eric Wieser (Jul 19 2021 at 17:18):

Can that be turned off in the pretty-printer?


Last updated: Dec 20 2023 at 11:08 UTC