Zulip Chat Archive
Stream: lean4
Topic: why doesn't this unify?
Kevin Buzzard (Nov 29 2022 at 10:09):
universe u v w
structure ApplicativeTransformation (F : Type u → Type v) [Applicative F] [LawfulApplicative F]
(G : Type u → Type w) [Applicative G] [LawfulApplicative G] : Type max (u + 1) v w where
app : ∀ α : Type u, F α → G α
preserves_pure' : ∀ {α : Type u} (x : α), app _ (pure x) = pure x
preserves_seq' : ∀ {α β : Type u} (x : F (α → β)) (y : F α), app _ (x <*> y) = app _ x <*> app _ y
variable (F : Type u → Type v) [Applicative F] [LawfulApplicative F]
variable (G : Type u → Type w) [Applicative G] [LawfulApplicative G]
instance : CoeFun (ApplicativeTransformation F G) fun _ => ∀ {α}, F α → G α :=
⟨ApplicativeTransformation.app⟩
variable {F G}
@[simp]
theorem coe_mk (f : ∀ α : Type u, F α → G α) (pp ps) :
(ApplicativeTransformation.mk f pp ps) = f :=
rfl
/-
type mismatch
ps
has type
?m.1275 : Sort ?u.1274
but is expected to have type
∀ (x : F (α✝ → β✝)) (y : F α✝), f β✝ (Seq.seq x fun x => y) = Seq.seq (f (α✝ → β✝) x) fun x => f α✝ y : Prop
-/
In Lean 3 this worked (this is from control.traversable.basic
in mathlib). I find these error messages confusing. There is an obvious solution to ?m.1275 : Sort ?u.1274 = <some proposition> : Prop
. Changing to (ps : _)
and variants didn't seem to fix the problem. What am I missing?
Kyle Miller (Nov 29 2022 at 10:16):
I think it's because Lean 4 unfolds coercions, so all that's left on the LHS of the =
is f
. Edit: with the version below, it's (ApplicativeTransformation.mk f pp ps).app
on the LHS, so this theory isn't right.
Kyle Miller (Nov 29 2022 at 10:17):
I'm still a bit confused by what's going on, but giving the full types works:
theorem coe_mk (f : ∀ α : Type u, F α → G α)
(pp : ∀ {α : Type u} (x : α), f _ (pure x) = pure x)
(ps : ∀ {α β : Type u} (x : F (α → β)) (y : F α), f _ (x <*> y) = f _ x <*> f _ y) :
(ApplicativeTransformation.mk f pp ps) = f :=
rfl
but there's no point for it being a @[simp]
lemma since it's just f = f
in the end (at least that's the error the attribute reports. When I #print
the lemma I see a more complicated type... Ah, the LHS is (ApplicativeTransformation.mk f pp ps).app
, which is something simp
will already simplify?)
Adam Topaz (Nov 29 2022 at 16:31):
It has to do with the implicit variables in preserves_pure' and preservsed_seq' (but I can't say I understand why!)
universe u v w
structure ApplicativeTransformation (F : Type u → Type v) [Applicative F] [LawfulApplicative F]
(G : Type u → Type w) [Applicative G] [LawfulApplicative G] : Type max (u + 1) v w where
app : ∀ α : Type u, F α → G α
preserves_pure' : ∀ (α : Type u) (x : α), app _ (pure x) = pure x
preserves_seq' : ∀ (α β : Type u) (x : F (α → β)) (y : F α), app _ (x <*> y) = app _ x <*> app _ y
variable (F : Type u → Type v) [Applicative F] [LawfulApplicative F]
variable (G : Type u → Type w) [Applicative G] [LawfulApplicative G]
instance : CoeFun (ApplicativeTransformation F G) fun _ => ∀ {α}, F α → G α :=
⟨ApplicativeTransformation.app⟩
variable {F G}
@[simp]
theorem coe_mk (f : ∀ (α : Type u), F α → G α) (pp ps) :
(ApplicativeTransformation.mk f pp ps) = f :=
rfl
^--- that works
Adam Topaz (Nov 29 2022 at 16:32):
Maybe hygiene has something to do with it?
Kevin Buzzard (Nov 29 2022 at 19:45):
Oh nice! So this looks like a bug?
Kevin Buzzard (Nov 29 2022 at 20:15):
def foo1mk (_ : ∀ (α : Type) (a : α), a = a) : Nat := 37
def foo2mk (_ : ∀ {α : Type} (a : α), a = a) : Nat := 37 -- implicit binder
example (x) : foo1mk x = foo1mk x := rfl -- works
example (x : ∀ {α : Type} (a : α), a = a) : foo2mk x = foo2mk x := rfl -- works
example (x) : foo2mk x = foo2mk x := rfl -- fails
/-
type mismatch
x
has type
?m.114 : Sort ?u.113
but is expected to have type
∀ (a : α✝), a = a : Prop
-/
Should I open an issue or is this expected behaviour?
Scott Morrison (Nov 29 2022 at 20:39):
I'm not sure. In lean3 we have:
def foo1mk (_ : ∀ (α : Type) (a : α), a = a) : nat := 37
def foo2mk (_ : ∀ {α : Type} (a : α), a = a) : nat := 37 -- implicit binder
example (x) : foo1mk x = foo1mk x := rfl -- works
example (x : ∀ {α : Type} (a : α), a = a) : foo2mk x = foo2mk x := rfl -- fails
example (x) : foo2mk x = foo2mk x := rfl -- fails
Kevin Buzzard (Nov 29 2022 at 20:43):
But this works in Lean 3: https://github.com/leanprover-community/mathlib/blob/cb48031ce12812ece794b782299def24bd8daba0/src/control/traversable/basic.lean#L90
Kevin Buzzard (Nov 29 2022 at 20:52):
-- Lean 3
def foo2mk (_ : ∀ {α : Type} (a : α), a = a) : nat := 37
example (x) : foo2mk x = 37 := rfl -- works
example (x) : foo2mk x = foo2mk x := rfl -- fails on second foo2mk
I am now completely bewildered.
Gabriel Ebner (Nov 29 2022 at 21:12):
I think this is the implicit lambdas feature in action (lean inserts fun {alpha} => automatically).
Gabriel Ebner (Nov 29 2022 at 21:13):
It might work if you write foo2mk @x
Kevin Buzzard (Nov 29 2022 at 22:12):
Thanks! Yes this @
trick fixes it (in both Lean 3 and Lean 4), although I don't really understand why; my mental model of what's going on must be wrong.
Mario Carneiro (Nov 29 2022 at 22:26):
The @
operator does two things:
- When applied to an application like
@foo x y z
(or@(f a) x y z
for that matter), it will elaborate the application partfoo x y z
with all implicit arguments as explicit. So for example iffoo
orf a
here had the type∀ {x y z : ℕ}, ℕ
thenx y z
would be passed in instead of using_ _ _
for those arguments and giving a type error. This is the normal use of@
from lean 3. - When used in a context where the expected type is an implicit lambda like
foo @_
wherefoo : (∀ {x : ℕ}, ℕ) → ℕ
, it prevents automatic insertion offun x =>
. That is,foo 0
is interpreted the same asfoo @(fun _ => 0)
. This is a lean 4 original.
Notice that the behavior (1) affects the elaboration of the thing inside the expression, while (2) affects the context around the expression (the expected type). The @
simultaneously affects both but you can get just one or the other behavior by using (@e)
or @(e)
as appropriate.
Mario Carneiro (Nov 29 2022 at 22:29):
The present issue has to do with behavior (2). When you use foo2mk @x
it will pass x
directly to foo2mk
rather than doing foo2mk @(fun _ => x)
like it normally would. Because the type of x
is unknown, this would cause it to get the type x : ∀ (a : ?α), a = a
and then the second application will fail.
Leonardo de Moura (Nov 29 2022 at 22:37):
Pushed a small improvement for the implicit lambda feature. All examples in this thread have been included in the test suite, and are working without the @
annotation.
https://github.com/leanprover/lean4/commit/3e45060dd52c13ee4904da1ccf6279df154f1a8a
Last updated: Dec 20 2023 at 11:08 UTC