Zulip Chat Archive

Stream: general

Topic: Typeclass inference on option.rec


Pierre-Alexandre Bazin (Mar 31 2022 at 11:24):

universes u v
variables {ι : Type u} {α : Type v} {β : ι  Type v}

section
variables [has_zero α] [Π i, has_zero (β i)]
instance inst0 : Π i, has_zero (option.rec α β i) :=
λ i, option.rec infer_instance infer_instance i --doesn't find it otherwise
end

section
variables [add_monoid α] [Π i, add_monoid (β i)]
instance inst : Π i, add_monoid (option.rec α β i) :=
λ i, option.rec infer_instance infer_instance i --doesn't find it otherwise

instance inst' : add_monoid (Π₀ i, option.rec α β i) :=
@dfinsupp.add_monoid (option ι) (λ i, option.rec α β i) inst --doesn't work
end

The reason it doesn't work is because the first Π₀ i, option.rec α β iis actually @dfinsupp (option ι) (λ i, option.rec α β i) inst0,
whereas @dfinsupp.add_monoid (option ι) (λ i, option.rec α β i) inst actually gives an add_monoid structure to
@dfinsupp (option ι) (λ i, option.rec α β i) (λ i, @add_monoid.to_has_zero _ (inst i)). (actually there's an extra step between add_monoid and has_zero but it doesn't matter)

The two Π i, has_zero (option.rec α β i) instances should be defeq but it doesn't see it (probably because it need some helper instances to build these). How can I avoid getting this error ?

Eric Wieser (Mar 31 2022 at 11:28):

I don't think using recursors to define typeclass instances is safe

Pierre-Alexandre Bazin (Mar 31 2022 at 11:29):

but how can I avoid this ?

Eric Wieser (Mar 31 2022 at 11:29):

The problem is roughly the same as the fact that (λ n, 2 * nat.rec x f n) is not the same as (λ n, nat.rec (2 * x) (2 * f) n)

Eric Wieser (Mar 31 2022 at 11:30):

Lean can't unfold the recursor unless it knows i

Eric Wieser (Mar 31 2022 at 11:30):

Which means it can't unify diamonds in the typeclass heirarchy for a general i

Eric Wieser (Mar 31 2022 at 11:31):

I tried something similar with sum.elim a while ago, see https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Instances.20on.20.60sum.2Eelim.20A.20B.20i.60/near/218484619

Pierre-Alexandre Bazin (Mar 31 2022 at 11:34):

this is indeed exactly the problem, as unfolding everything it's basically λ i, add_comm_monoid.to_has_zero (option.rec α β i) vs λ i, option.rec (add_comm_monoid.to_has_zero α) (add_comm_monoid.to_has_zero β) i

Pierre-Alexandre Bazin (Mar 31 2022 at 11:34):

But I don't know how I could avoid the use of option.rec

Eric Wieser (Mar 31 2022 at 11:37):

Can you give some more context?

Pierre-Alexandre Bazin (Mar 31 2022 at 11:37):

I'm trying to add one term to a dfinsupp/direct sum

Eric Wieser (Mar 31 2022 at 11:38):

Once way you could avoid this is to use option.rec to define has_zero, has_one, etc:

instance : has_zero (option.rec α β i) := { zero := option.rec 0 0 i }

Eric Wieser (Mar 31 2022 at 11:38):

And then build add_monoid by using option.rec in each proof field

Pierre-Alexandre Bazin (Mar 31 2022 at 11:38):

so I have a noncomputable def equiv_prod_dfinsupp : (Π₀ i, option.rec α β i) ≃ α × Π₀ i, β i := ... and I want to extend it to an ≃+

Eric Wieser (Mar 31 2022 at 11:38):

The key thing is to push the option.rec inside all the constructors

Eric Wieser (Mar 31 2022 at 11:39):

(Π₀ i : fin n.succ, α i) ≃ α × Π₀ i : fin n, α i.succ would be one way out

Eric Wieser (Mar 31 2022 at 11:40):

Or (Π₀ i : option X, α i) ≃ α none × Π₀ i : X, α (some i)

Pierre-Alexandre Bazin (Mar 31 2022 at 11:41):

the latter seems better because it also works with infinite direct sums

Eric Wieser (Mar 31 2022 at 11:41):

I'd go for that option first, and come back to option.rec instances if that has issues

Pierre-Alexandre Bazin (Mar 31 2022 at 11:41):

(but actually the former is my use case so I was considering doing only this first at some point)


Last updated: Dec 20 2023 at 11:08 UTC