Zulip Chat Archive
Stream: lean4
Topic: a question on elaboration order
Kenny Lau (Nov 03 2025 at 12:46):
I can get rid of the mathlib dependency later, but consider this:
import Mathlib
axiom Foo {ι A σ : Type*} [SetLike σ A] (𝒜 : ι → σ) (f : A) : Prop
variable (R A : Type*) [Field R] [Field A] [Algebra R A] (𝒜 : ℕ → Submodule R A) (f : 𝒜 67)
#check Foo 𝒜 f -- failed to synthesize SetLike (Submodule R A) ↥(𝒜 67)
I would expect that since SetLike takes an outParam, it should have expected f to have type A, instead of just taking the ↥(𝒜 67), right?
Kenny Lau (Nov 03 2025 at 12:47):
i.e. I expect it to automatically coerce f to A. is this possible?
Aaron Liu (Nov 03 2025 at 12:50):
so it first fills in the implicit argument, so you have @Foo ℕ ↥(𝒜 67) (Submodule R A) ?_ 𝒜 f
Aaron Liu (Nov 03 2025 at 12:51):
then it synthesizes the typeclass variable (expected type is SetLike (Submodule R A) ↥(𝒜 67)), finds a SetLike (Submodule R A) A, and when it tries to unify with the expected type it fails
Aaron Liu (Nov 03 2025 at 12:52):
but if you do
import Mathlib
axiom Foo {ι A σ : Type*} [SetLike σ A] (𝒜 : ι → σ) (f : A) : Prop
variable (R A : Type*) [Field R] [Field A] [Algebra R A] (𝒜 : ℕ → Submodule R A) (f : 𝒜 67)
#check Foo 𝒜 ↑f
then it works fine
Kenny Lau (Nov 03 2025 at 12:53):
works fine here but didn't work in my case (I still had to specify the type), or maybe it was just slower, which is still suboptimal
Kenny Lau (Nov 03 2025 at 12:54):
Aaron Liu said:
so it first fills in the implicit argument, so you have
@Foo ℕ (𝒜 67) (Submodule R A) ?_ 𝒜 fthen it synthesizes the typeclass variable (expected type is
SetLike (Submodule R A) ↥(𝒜 67)), finds aSetLike (Submodule R A) A, and when it tries to unify with the expected type it fails
right, that's how it works now, but I'm asking is this what it should do, and is there an easy way to change it
Kenny Lau (Nov 03 2025 at 12:54):
i'm saying that it should find SetLike (Submodule R A) A, and then try to elaborate f to have type A; i.e. i'm proposing that they should use a different algorithm when it seems outParams
Aaron Liu (Nov 03 2025 at 12:54):
well you have to fill in the holes for typeclass synthesis to work
Aaron Liu (Nov 03 2025 at 12:55):
otherwise you get SetLike ?_ ?_ and that's not solvable
Aaron Liu (Nov 03 2025 at 12:55):
and then once they're filled in you can't exactly un-fill them
Kenny Lau (Nov 03 2025 at 12:55):
sure, from 𝒜 you can infer SetLike (Submodule R A) ?_, but it should delay resolving f
Aaron Liu (Nov 03 2025 at 12:55):
why should it delay f and not some other thing?
Aaron Liu (Nov 03 2025 at 12:56):
what determines that f requires delaying?
Aaron Liu (Nov 03 2025 at 12:56):
we could just as well do f first and delay 𝒜
Kenny Lau (Nov 03 2025 at 13:01):
Aaron Liu said:
why should it delay
fand not some other thing?
@Foo ?_ ?_ ?_ ?_ ?_ ?_@Foo ℕ ?_ (Submodule R A) ?_ 𝒜 ?_@Foo ℕ A (Submodule R A) instSetLike 𝒜 ?_@Foo ℕ A (Submodule R A) instSetLike 𝒜 (@Subtype.val A (fun x => x ∈ 𝒜 67) f)
I'm saying that it should use the explicit parameters one at a time, and then fill in earlier blanks, and then use the next explicit parameter
Aaron Liu (Nov 03 2025 at 13:02):
that's an idea
Aaron Liu (Nov 03 2025 at 13:02):
oh this works too
import Mathlib
axiom Foo {ι A σ : Type*} [SetLike σ A] (𝒜 : ι → σ) (f : A) : Prop
variable (R A : Type*) [Field R] [Field A] [Algebra R A] (𝒜 : ℕ → Submodule R A) (f : 𝒜 67)
#check (Foo 𝒜) f
Kenny Lau (Nov 03 2025 at 13:02):
w0t
Aaron Liu (Nov 03 2025 at 13:03):
since it goes in order
Aaron Liu (Nov 03 2025 at 13:03):
like you wanted
Kenny Lau (Nov 03 2025 at 13:04):
yeah I understand how it works but I'm just shocked
Aaron Liu (Nov 03 2025 at 13:05):
probably anything most things that puts 𝒜 and f in separate docs#Lean.Parser.Term.app nodes will work
Kenny Lau (Nov 03 2025 at 13:06):
minimsed version:
notation:max "ℕ" => Nat
class SetLike (A : Type) (B : outParam Type) : Type where
protected coe : A → B → Prop
instance SetLike.instCoeSortType {A B : Type} [SetLike A B] : CoeSort A Type where
coe p := Subtype (SetLike.coe p)
axiom Submodule : Type → Type → Type
@[instance] axiom Submodule.setLike {R A : Type} : SetLike (Submodule R A) A
axiom Foo {ι A σ : Type} [SetLike σ A] (𝒜 : ι → σ) (f : A) : Prop
variable (R A : Type) (𝒜 : ℕ → Submodule R A) (f : 𝒜 67)
#check Foo 𝒜 f -- fails
-- workarounds:
#check Foo 𝒜 ↑f
#check Foo 𝒜 (f : A)
#check (Foo 𝒜) f -- thanks to Aaron
Aaron Liu (Nov 03 2025 at 13:07):
interestingly, Foo 𝒜 <| f does not work
Aaron Liu (Nov 03 2025 at 13:09):
so the parentheses are probably doing something maybe?
Robin Arnez (Nov 04 2025 at 07:37):
<| has a special case when the left-hand side is an application, in which case it won't generate a new app node but just extend the old one
Last updated: Dec 20 2025 at 21:32 UTC