Zulip Chat Archive

Stream: mathlib4

Topic: Bug in by_contra (implicit arguments)


Yury G. Kudryashov (Mar 15 2025 at 06:42):

example :  {n : Nat}, n = n := by
  by_contra h

creates assumptions n : Nat and n ≠ n instead of Not (∀ {n : Nat}, n = n).

Jovan Gerbscheid (Mar 15 2025 at 09:24):

It is a macro that turns into this:

example :  {n : Nat}, n = n := by
  refine Decidable.byContradiction fun h => ?_

which has the same problem.

Aaron Liu (Mar 15 2025 at 10:05):

This seems like something that can be fixed with a little @

Jovan Gerbscheid (Mar 15 2025 at 10:09):

Wow, why does that work?

A different solution I though of was to use apply Classical.byContractction; intro h

Eric Wieser (Mar 15 2025 at 10:12):

I assume the fix is @fun?

Eric Wieser (Mar 15 2025 at 10:12):

This is just the notation to disable implicit lambdas, which are to blame here

Jovan Gerbscheid (Mar 15 2025 at 10:12):

I interpreted it like this, which works:

example :  {n : Nat}, n = n := by
  refine @Classical.byContradiction _ fun h => ?_

Eric Wieser (Mar 15 2025 at 10:14):

Does my version also work?

Jovan Gerbscheid (Mar 15 2025 at 10:14):

No, it even introduces the variable like this:

example :  {n : Nat}, n = n := by
  refine Classical.byContradiction ?_

Jovan Gerbscheid (Mar 15 2025 at 10:21):

But the problem is indeed caused by an implicit lambda:

import Lean
import Qq

open Qq Lean Elab Term
elab "test" e:term : tactic => do
  let t := q( {n : Nat}, n = n)
  let e  elabTerm e t
  logInfo m! "{e}"

example :  {n : Nat}, n = n := by
  test Classical.byContradiction ?_ -- fun {n} => Classical.byContradiction ?m.976

Jovan Gerbscheid (Mar 15 2025 at 10:30):

It seems that it is a feature of @ notation that the implicit lambdas are turned off.

Jovan Gerbscheid (Mar 15 2025 at 10:37):

Here's another fun one:

import Batteries

example (h :  {n : Nat}, n = n) : True := by
  /-
  don't know how to synthesize implicit argument 'a'
    @absurd (?m.8343 = ?m.8343) True h ?m.8344
  context:

  h : ∀ {n : Nat}, n = n
  ⊢ Prop
  -/
  absurd h

Jovan Gerbscheid (Mar 15 2025 at 10:41):

And exfalso also introduces implicit variables:

example :  {n : Nat}, n = n := by
  exfalso

Jovan Gerbscheid (Mar 15 2025 at 11:36):

I think no_implicit_lambda% is also supposed to fix this, but it has some surprising behaviour:

import Lean
import Qq

open Qq Lean Elab Term
elab "test" e:term : tactic => do
  let t := q( {n : Nat}, n = n)
  let e  elabTerm e t
  logInfo m! "{e}"

set_option pp.explicit true
example :  {n : Nat}, n = n := by
  test -- @Classical.byContradiction (∀ {n : Nat}, @Eq Nat n n) (fun h => ?m.979) ?m.984
    no_implicit_lambda% (Classical.byContradiction fun h => ?_)

Yury G. Kudryashov (Mar 15 2025 at 20:58):

See https://github.com/leanprover-community/batteries/pull/1162 by @Alex J. Best

Eric Wieser (Mar 15 2025 at 23:45):

Eric Wieser said:

Does my version also work?

example :  {n : Nat}, n = n := by
  refine Classical.byContradiction @fun h => ?_
  sorry

Seems to work fine for me?

Jovan Gerbscheid (Mar 15 2025 at 23:46):

On Lean web, it gives me

n : Nat
h : ¬n = n
 False

Which is what we don't want.

Eric Wieser (Mar 15 2025 at 23:47):

Sorry, my mistake

Eric Wieser (Mar 15 2025 at 23:51):

This works:

example :  {n : Nat}, n = n := by
  refine @(Classical.byContradiction ?_)
  sorry

Aaron Liu (Mar 15 2025 at 23:54):

never seen the @(...) before

Aaron Liu (Mar 15 2025 at 23:54):

what does it do

Eric Wieser (Mar 16 2025 at 00:00):

Suppresses implicit lambdas, somewhat

Eric Wieser (Mar 16 2025 at 00:04):

A full fix:

example :  {n : Nat}, n = n := by
  refine (Classical.byContradiction fun h => ?_ :)

Kyle Miller (Mar 16 2025 at 00:05):

In particular, @(t) elaborates t with the implicit lambda flag set to false. The flag doesn't get propagated to subterms, but it does propagate through macro expansions. Normally, with some exceptions, implicit and instance implicit binders in the expected type get "auto-introed" by wrapping the elaborated result in a lambda expression (hence, "implicit lambda"; I guess it's punning "implicit" in the "done implicitly" sense and the "implicit binder" sense).

Kyle Miller (Mar 16 2025 at 00:13):

Here's another option:

example :  {n : Nat}, n = n := by
  refine_lift Classical.byContradiction ?_; intro h

Kyle Miller (Mar 16 2025 at 00:13):

I'm really confused why it doesn't seem possible to put fun h => ?_ into the refine_lift, without using (... :)

Eric Wieser (Mar 24 2025 at 14:45):

Yury G. Kudryashov said:

See https://github.com/leanprover-community/batteries/pull/1162 by Alex J. Best

This is now merged

Aaron Liu (Mar 24 2025 at 15:25):

(deleted)


Last updated: May 02 2025 at 03:31 UTC