Zulip Chat Archive

Stream: general

Topic: more type class inference issues


Kevin Buzzard (Apr 19 2018 at 18:59):

It seems to me that for classes like ringdefined in core lean or mathlib, you are kind of supposed to use type class inference to make them work.

Kevin Buzzard (Apr 19 2018 at 18:59):

For example, class is_ring_hom {α : Type u} {β : Type v} [ring α] [ring β] (f : α → β) : Prop := ... is now in mathlib

Kevin Buzzard (Apr 19 2018 at 19:00):

now I don't actually know how to make type class inference work in all cases, so I spend some of my time working around it.

Kevin Buzzard (Apr 19 2018 at 19:01):

Here's an example. I have the following structure in my code:

Kevin Buzzard (Apr 19 2018 at 19:01):

structure presheaf_of_rings (α : Type*) [T : topological_space α] extends presheaf_of_types α :=
(Fring :  {U} (OU : T.is_open U), comm_ring (F OU))
(res_is_ring_morphism :  (U V : set α) (OU : T.is_open U) (OV : T.is_open V) (H : V  U),
  is_ring_hom (res U V OU OV H))

Kevin Buzzard (Apr 19 2018 at 19:03):

Yesterday, is_ring_hom was about comm_ring, and I used it in my code via @is_ring_hom _ _ (FPR.Fring HU) (GPR.Fring HU) ..., explicitly giving the proof that something was a comm_ring.

Kevin Buzzard (Apr 19 2018 at 19:03):

But now it's changed to ring and so either I figure out a way of explicitly turning a comm_ring into a ring

Kevin Buzzard (Apr 19 2018 at 19:04):

or I ask here about how I should be doing this properly.

Kevin Buzzard (Apr 19 2018 at 19:04):

In short, Lean / mathlib seems to want me, by default, to prove that things are rings by type class inference.

Kevin Buzzard (Apr 19 2018 at 19:05):

How do I ensure that every time I access a presheaf_of_rings as defined above, presheaf_of_rings.Fring is added to the type class inference system?

Kevin Buzzard (Apr 19 2018 at 19:07):

Is there some clever trick involving an instance statement directly after the definition of presheaf_of_rings?

Kevin Buzzard (Apr 19 2018 at 19:11):

Oh yeah :-)

Kevin Buzzard (Apr 19 2018 at 19:11):

instance presheaf_of_rings_Fring (α : Type*) [T : topological_space α] {U : set α} (FPR : presheaf_of_rings α) (OU : T.is_open U) : comm_ring (FPR.F OU) :=
FPR.Fring OU

Kevin Buzzard (Apr 19 2018 at 19:11):

As you were :-)

Kevin Buzzard (Apr 19 2018 at 19:50):

What does this mean?

Kevin Buzzard (Apr 19 2018 at 19:50):

structure presheaf_of_rings (α : Type*) [T : topological_space α] extends presheaf_of_types α :=
[Fring :  {U} (OU : T.is_open U), comm_ring (F OU)]
(res_is_ring_morphism :  (U V : set α) (OU : T.is_open U) (OV : T.is_open V) (H : V  U),
  is_ring_hom (res U V OU OV H))

Kevin Buzzard (Apr 19 2018 at 19:50):

Is that a thing? It doesn't seem to be a thing.

Chris Hughes (Apr 19 2018 at 19:51):

comm_ring.to_ring might help

Chris Hughes (Apr 19 2018 at 19:53):

attribute [instance] presheaf_of_rings.Fring might also help

Chris Hughes (Apr 19 2018 at 19:55):

Just add that ^ line after the definition of presheaf_of_rings

Kevin Buzzard (Apr 19 2018 at 20:09):

Oh that's a better way :-) Thanks Chris, I'm glad I asked now.

Kevin Buzzard (Apr 19 2018 at 20:12):

I specifically wanted to avoid comm_ring.to_ring as I am pretty sure that the whole point of type class inference is that the end user shouldn't have to use such functions.

Kevin Buzzard (Apr 19 2018 at 20:43):

Actually, is the following a potential problem with the type class system:

Kevin Buzzard (Apr 19 2018 at 20:44):

My understanding (incomplete) of something Johannes was saying a few days ago to Patrick, was that the reason topological_space is defined as a structure with the class attribute added later, rather than a class directly, was that there were occasions when you might want to consider more than one topological space structure on a given type.

Kevin Buzzard (Apr 19 2018 at 20:45):

but ring is defined as a class in core lean

Kevin Buzzard (Apr 19 2018 at 20:46):

so what about the person who wants to prove theorems about putting different ring structures on a type?

Kevin Buzzard (Apr 19 2018 at 20:46):

Are they forced to abandon the type class system, and then they really would have to learn the names of all the theorems mapping a ring to an additive group etc?

Kevin Buzzard (Apr 19 2018 at 20:50):

And here's another question: what if the ring instance is in the same structure?

Kevin Buzzard (Apr 19 2018 at 20:50):

structure presheaf_of_rings_on_basis {X : Type u} [TX : topological_space X]
  {B : set (set X)} (HB : topological_space.is_topological_basis B) extends presheaf_of_types_on_basis HB :=
(Fring :  {U} BU, comm_ring (F BU))
(res_is_ring_morphism :  {U V} (BU : U  B) (BV : V  B) (H : V  U),
  @is_ring_hom _ _ (@Fring U BU) (Fring BV) (@res U V BU BV H))

Kevin Buzzard (Apr 19 2018 at 20:52):

Here a presheaf_of_rings_on_basis has Fring saying something is a commutative ring, and then res_is_ring_morphism which immediately wants to use type class inference to deduce that Fring U BU is a ring. Now do I really have to use comm_ring.to_ring?

Kevin Buzzard (Apr 19 2018 at 20:55):

structure presheaf_of_rings_on_basis {X : Type u} [TX : topological_space X]
  {B : set (set X)} (HB : topological_space.is_topological_basis B) extends presheaf_of_types_on_basis HB :=
(Fring :  {U} (BU : U  B), comm_ring (F BU))
(res_is_ring_morphism :  {U V} (BU : U  B) (BV : V  B) (H : V  U),
  @is_ring_hom _ _ (@comm_ring.to_ring _ (Fring BU)) (@comm_ring.to_ring _ (Fring BV)) (@res U V BU BV H))

Kevin Buzzard (Apr 19 2018 at 20:56):

Type class inference is failing me badly here. Sorry for no MWE, hopefully people can see the problem; Lean wants me to use type class inference to prove that commutative rings are rings but I don't know how to make this happen in this situation.

Mario Carneiro (Apr 19 2018 at 20:57):

that's what the brackets inside the structure are for

Kevin Buzzard (Apr 19 2018 at 20:58):

?

Kevin Buzzard (Apr 19 2018 at 20:58):

Oh!

Kevin Buzzard (Apr 19 2018 at 20:59):

:-)

Kevin Buzzard (Apr 19 2018 at 20:59):

structure presheaf_of_rings_on_basis {X : Type u} [TX : topological_space X]
  {B : set (set X)} (HB : topological_space.is_topological_basis B) extends presheaf_of_types_on_basis HB :=
[Fring :  {U} (BU : U  B), comm_ring (F BU)]
(res_is_ring_morphism :  {U V} (BU : U  B) (BV : V  B) (H : V  U),
  is_ring_hom (@res U V BU BV H))

Kevin Buzzard (Apr 19 2018 at 21:00):

So just to be clear -- the square brackets inside the structure trigger type class inference only within the structure definitions?

Mario Carneiro (Apr 19 2018 at 21:01):

I think they also mark it as an instance, but you should #print to be sure

Kevin Buzzard (Apr 19 2018 at 21:01):

I don't think they do

Kevin Buzzard (Apr 19 2018 at 21:01):

because that was what prompted the question about why the square brackets within the structure definition was even a thing

Kevin Buzzard (Apr 19 2018 at 21:01):

earlier

Mario Carneiro (Apr 19 2018 at 21:03):

you shouldn't need @res either

Kevin Buzzard (Apr 19 2018 at 21:04):

yes, that's gone now

Kevin Buzzard (Apr 19 2018 at 21:05):

But your change of is_ring_hom from [comm_ring] to [ring] has thrown up one final type class inference issue which I can't solve

Kevin Buzzard (Apr 19 2018 at 21:05):

possibly because it's not solvable

Kevin Buzzard (Apr 19 2018 at 21:05):

I think I do need an MWE for this one

Kevin Buzzard (Apr 19 2018 at 21:11):

Oh no it's Ok, indeed I am now pretty convinced that the square brackets in the structure definition do not insert anything into the type class inference system globally

Kevin Buzzard (Apr 19 2018 at 21:12):

because my final problem was solved by Chris' instance trick.

Kevin Buzzard (Apr 19 2018 at 21:12):

Oh this is great. I got stuck on these problems before and blamed it on the type class inference system not being smart enough.

Kevin Buzzard (Apr 19 2018 at 21:12):

I should have asked for help earlier.

Kevin Buzzard (Apr 19 2018 at 21:13):

Patrick said the same thing -- I told him to give up on coercions because they weren't smart enough

Kevin Buzzard (Apr 19 2018 at 21:13):

and he pointed out that whenever he'd got stuck before, you (Mario) had had a trick which got him through.

Kevin Buzzard (Apr 19 2018 at 21:18):

Here's a weird question. It feels to me like comm_ring.to_ring should not be the kind of function which end users have to worry about, because when the devs made ring a typeclass they are somehow declaring that Lean will automatically take care of inferences of this nature.

Kevin Buzzard (Apr 19 2018 at 21:18):

Am I right in thinking that an end user should only have to invoke comm_ring.to_ring in exceptional circumstances?

Kevin Buzzard (Apr 19 2018 at 21:19):

(says the person who just managed to avoid all uses of it when his code broke in lots of places)

Kevin Buzzard (Apr 19 2018 at 21:19):

(when a comm_ring changed to a ring)

Kevin Buzzard (Apr 19 2018 at 21:21):

Aah, more generally should an end user never have to explicitly invoke any theorem tagged with the instance attribute?

Kevin Buzzard (Apr 19 2018 at 21:22):

(unless they are putting more than one structure of a typeclass onto one type, say)

Chris Hughes (Apr 19 2018 at 22:16):

Sorry to hijack your thread, but I have a typeclass issue of my own

import data.int.modeq

instance Zmod_setoid {n : } : setoid  :=
{ r := int.modeq n,
  iseqv := int.modeq.refl, @int.modeq.symm n, @int.modeq.trans n }

def Zmod (n : ) : Type := quotient (@Zmod_setoid n)

private def add_aux {n : } (a b : Zmod n) : Zmod n :=
quotient.lift_on₂ a b (λ a b, a + b) sorry

It cannot infer the setoid instance, probably because it requires an argument. Not sure of a good solution to this.

Mario Carneiro (Apr 19 2018 at 22:22):

This is a common problem; I think the lift_on recursor does not correctly deliver the expected type to the lambda. The usual solution is to add an ascription at the lambda:

private def add_aux {n : ℤ} (a b : Zmod n) : Zmod n :=
quotient.lift_on₂ a b (λ a b, (⟦a + b⟧ : Zmod n)) sorry

Chris Hughes (Apr 19 2018 at 22:25):

Still not working I'm getting this message

synthesized type class instance is not definitionally equal to expression inferred by typing rules, synthesized
  ⁇
inferred
  Zmod_setoid n

Kevin Buzzard (Apr 19 2018 at 23:24):

import data.int.modeq

instance Zmod_setoid {n : } : setoid  :=
{ r := int.modeq n,
  iseqv := int.modeq.refl, @int.modeq.symm n, @int.modeq.trans n }

example : setoid  := by apply_instance -- fails

Kevin Buzzard (Apr 19 2018 at 23:24):

I'm not sure that I understand how parametrized instances work.

Kevin Buzzard (Apr 19 2018 at 23:29):

import data.int.modeq

instance Zmod_setoid {n : } : setoid  :=
{ r := int.modeq n,
  iseqv := int.modeq.refl, @int.modeq.symm n, @int.modeq.trans n }

def Zmod (n : ) : Type := quotient (@Zmod_setoid n)

#check (3 : Zmod 5) -- failed to synthesize type class instance for setoid ℤ

Kevin Buzzard (Apr 19 2018 at 23:29):

I'm even less sure now

Kevin Buzzard (Apr 19 2018 at 23:32):

#check (⟦(3 : ℤ)⟧ : Zmod 5 gives

Kevin Buzzard (Apr 19 2018 at 23:32):

⁇ : Zmod 5 for information check result (in green)

Kevin Buzzard (Apr 19 2018 at 23:33):

and fails to synthesize the instance

Simon Hudon (Apr 19 2018 at 23:36):

Try:

import data.int.modeq

@[reducible]
def Zmod (n : ℤ) : Type := ℤ

instance Zmod_setoid {n : ℤ} : setoid (Zmod n) :=
{ r := int.modeq n,
  iseqv := ⟨int.modeq.refl, @int.modeq.symm n, @int.modeq.trans n⟩ }

example {n : ℤ} : setoid (Zmod n) := by apply_instance

#check ⟦ (3 : Zmod 5) ⟧

Simon Hudon (Apr 19 2018 at 23:38):

The problem is that instance inference is only working with (in your example) to find a setoid instance. It's not enough information to infer the n parameter. Now, I added a synonym for which provides that information.

Kevin Buzzard (Apr 19 2018 at 23:52):

import data.int.modeq

@[reducible]
def Z_aux (n : ) : Type := 

instance Zmod_setoid {n : } : setoid (Z_aux n) :=
{ r := int.modeq n,
  iseqv := int.modeq.refl, @int.modeq.symm n, @int.modeq.trans n }

example {n : } : setoid (Z_aux n) := by apply_instance

def Zmod (n : ) : Type := quotient (@Zmod_setoid n)

#check ( 3  : Zmod 5) -- 3 is interpreted as being in Z_aux 5 and this works

private def add_aux {n : } (a b : Zmod n) : Zmod n :=
quotient.lift_on₂ a b (λ a b, (a + b : Zmod n)) sorry -- no error yet

Kevin Buzzard (Apr 19 2018 at 23:53):

As a mathematician I'm a bit uneasy about having a thing which is Z but which is called Zmod n

Kevin Buzzard (Apr 19 2018 at 23:53):

so I renamed it Z_aux, but your trick is excellent all the same :-)

Kevin Buzzard (Apr 19 2018 at 23:53):

I was worried the check would fail because Lean wouldn't push 3 into Z_aux 5

Kevin Buzzard (Apr 19 2018 at 23:55):

setoid is a class and this is in core lean.

Kevin Buzzard (Apr 19 2018 at 23:55):

I think this means that it's quite hard to have more than one instance of a setoid structure on a given type

Kevin Buzzard (Apr 19 2018 at 23:55):

Simon's trick shows how to get around this, by making lots of types, one for each structure

Kevin Buzzard (Apr 19 2018 at 23:56):

it's evil :-)

Simon Hudon (Apr 19 2018 at 23:56):

In general, if you need more than one instance of a class for a given type, it should make you suspicious

Mario Carneiro (Apr 19 2018 at 23:56):

it's also a good way to handle the multiple rings problem

Kevin Buzzard (Apr 19 2018 at 23:56):

yes

Kevin Buzzard (Apr 19 2018 at 23:56):

I don't think I'd seen it before

Simon Hudon (Apr 19 2018 at 23:56):

But you can also name the quotient instead of Z:

Simon Hudon (Apr 19 2018 at 23:57):

instance Zmod_setoid (n : ) : setoid (Zmod n) :=
{ r := int.modeq n,
  iseqv := int.modeq.refl, @int.modeq.symm n, @int.modeq.trans n }

def Zmod' (n : ) : Type := quotient (Zmod_setoid n)

#check ( 3  : Zmod' 5)

Simon Hudon (Apr 19 2018 at 23:57):

And if you equip Zmod' 5 with has_one, has_zero and has_add, #check (3 : Zmod' 5) should work

Kevin Buzzard (Apr 20 2018 at 00:01):

variables (Y : Type) [has_add Y] [has_one Y]
#check (3 : Y)

Kevin Buzzard (Apr 20 2018 at 00:01):

no need for zero ;-)

Simon Hudon (Apr 20 2018 at 00:01):

Even better!

Kevin Buzzard (Apr 20 2018 at 00:01):

sort of...

Kevin Buzzard (Apr 20 2018 at 00:02):

:-)

Simon Hudon (Apr 20 2018 at 00:02):

Simon's trick shows how to get around this, by making lots of types, one for each structure

it's evil :-)

I disagree. If you want the structure to be inferred implicitly, the information must be somewhere. The alternative is to have a different + / * operator for each one of those structures: +_mod_5 / *_mod_5. That would be ugly and evil!

Kevin Buzzard (Apr 20 2018 at 00:03):

If setoid were a structure rather than a class, do you think Chris' code would be OK?

Kevin Buzzard (Apr 20 2018 at 00:03):

The quotient knows the equivalence relation, and the information distinguishing the quotient types is in the equivalence relation

Kevin Buzzard (Apr 20 2018 at 00:06):

variables (Y : Type) [has_add Y] [has_one Y]

Kevin Buzzard (Apr 20 2018 at 00:06):

I think I just defined the positive integers :-)

Simon Hudon (Apr 20 2018 at 00:06):

Yeah I think that would be good. Maybe rather than making setoid a structure, just make Zmod_setoid into a definition because it is not unique

Kevin Buzzard (Apr 20 2018 at 00:07):

then you'll lose access to the \[[ notation

Kevin Buzzard (Apr 20 2018 at 00:07):

this goes back to the thing I was talking about earlier

Kevin Buzzard (Apr 20 2018 at 00:07):

once setoid is deemed to be a class

Kevin Buzzard (Apr 20 2018 at 00:08):

then pretty much whenever it's mentioned in a definition or theorem, it's in a square bracket

Simon Hudon (Apr 20 2018 at 00:08):

I think I just defined the positive integers :-)

That looks like the Church numerals

Simon Hudon (Apr 20 2018 at 00:08):

Sorry, I kind of jumped in the middle your conversation

Kevin Buzzard (Apr 20 2018 at 00:09):

so it's a pain to work with if you decide not to use the type class inference system

Simon Hudon (Apr 20 2018 at 00:09):

Yes, I see now

Kevin Buzzard (Apr 20 2018 at 00:09):

As Mario points out, it's the same sort of thing as the (hypothetical but not completely impossible) possibility of having more than one ring structure on a type

Simon Hudon (Apr 20 2018 at 00:09):

Is it ever necessary to have it inferred?

Kevin Buzzard (Apr 20 2018 at 00:10):

it's just inconvenient not to have it inferred, if Lean wants it to be inferred.

Kevin Buzzard (Apr 20 2018 at 00:10):

That was what I discovered when I had a commutative ring earlier -- if you use the type class inference system then you also automatically have a ring, an additive group, and a whole bunch of other things

Kevin Buzzard (Apr 20 2018 at 00:11):

and if you don't then you're stuck making all of these yourself

Simon Hudon (Apr 20 2018 at 00:11):

What if you skip \[[ and instead rely on coe to convert integers to Zmod and has_one / has_add to use numerals?

Kevin Buzzard (Apr 20 2018 at 00:13):

I guess the proof of the pudding would be in the eating

Kevin Buzzard (Apr 20 2018 at 00:14):

I was fine explictly writing my proofs that various types were commutative rings up to a point

Kevin Buzzard (Apr 20 2018 at 00:14):

and then it got inconvenient and then I figured out how to use type class inference.

Kevin Buzzard (Apr 20 2018 at 00:14):

Those things aren't quite church numerals

Kevin Buzzard (Apr 20 2018 at 00:14):

as far as I can see at least

Kevin Buzzard (Apr 20 2018 at 00:15):

but they do have a similar flavour

Kevin Buzzard (Apr 20 2018 at 00:19):

def hudon_numeral := Π (Y : Type), (Y  Y  Y)  Y  Y
def one : hudon_numeral := λ Y h_add h_one, h_one
def two : hudon_numeral := λ Y h_add h_one, h_add h_one h_one

Kevin Buzzard (Apr 20 2018 at 00:19):

etc

Simon Hudon (Apr 20 2018 at 00:20):

Ah yes I see! 0 is missing and Church encodes succ rather than add

Chris Hughes (Apr 20 2018 at 11:05):

Any advice about how to deal with this issue?

def Zmod_fintype {n : } (hn : n  0) : fintype (Zmod n) :=
fintype.of_equiv _ (equiv_fin hn).symm

I can't make this an instance, because it's only true if n ≠ 0

Kevin Buzzard (Apr 20 2018 at 11:14):

Why not let n be in pnat (positive integers) instead of Z?

Chris Hughes (Apr 20 2018 at 11:18):

Probably the best thing. Alternative is to define the equivalence relation differently in the case n = 0, so Zmod 0 is a fintype.

Chris Hughes (Apr 20 2018 at 11:26):

Then there's also the issue of proving it's a field in the case prime p

Kenny Lau (Apr 20 2018 at 11:27):

fintype (Zmod $ nat.succ m)

Chris Hughes (Apr 20 2018 at 11:29):

n is an int currently

Kevin Buzzard (Apr 20 2018 at 17:34):

I have another type class inference issue and this one is rather frustrating.

Kevin Buzzard (Apr 20 2018 at 17:34):

I am making a definition, so I really want to stay in term mode.

Kevin Buzzard (Apr 20 2018 at 17:34):

I wrote down something which should work

Kevin Buzzard (Apr 20 2018 at 17:35):

and Lean complained that it could not prove that a certain composition of two maps was a ring homomorphism.

Kevin Buzzard (Apr 20 2018 at 17:35):

So I tried again in tactic mode

Kevin Buzzard (Apr 20 2018 at 17:35):

(each map is a ring hom, with an instance, and the composite of two ring homs is a ring hom, and this is an instance too, so it should work)

Kevin Buzzard (Apr 20 2018 at 17:36):

and in tactic mode I have managed to get Lean into a state where the goal is to show that the map is a ring hom (I did this using refine)

Kevin Buzzard (Apr 20 2018 at 17:36):

and apply_instance fails

Kevin Buzzard (Apr 20 2018 at 17:36):

but show ([cut and paste the goal])

Kevin Buzzard (Apr 20 2018 at 17:36):

followed by apply_instance succeeds.

Kevin Buzzard (Apr 20 2018 at 17:37):

In term mode, the proof should look like this:

Kevin Buzzard (Apr 20 2018 at 17:37):

to_fun := away.extend_map_of_im_unit ((of_comm_ring (away f) _) ∘ (of_comm_ring R (powers f))) H,

Kevin Buzzard (Apr 20 2018 at 17:37):

(it's some part of a structure I'm defining)

Kevin Buzzard (Apr 20 2018 at 17:38):

but away.extend_map_of_im_unit requires that the map (a composite of two ring homs) is a ring hom

Kevin Buzzard (Apr 20 2018 at 17:39):

So here it feels to me like Lean is not working as well as it could be.

Kevin Buzzard (Apr 20 2018 at 17:39):

But I don't have any feeling as to why not

Kevin Buzzard (Apr 20 2018 at 17:41):

If I set pp.all true I can see that the show command is doing something

Kevin Buzzard (Apr 20 2018 at 17:41):

but unfortunately these are complex maps defined between complex rings

Kevin Buzzard (Apr 20 2018 at 17:41):

and so I am having trouble figuring out what I have done wrong

Kevin Buzzard (Apr 20 2018 at 17:41):

and whether it's Lean's fault or mine

Kevin Buzzard (Apr 20 2018 at 17:45):

Here are the two (rather lengthy) goals.

Kevin Buzzard (Apr 20 2018 at 17:45):

https://gist.github.com/kbuzzard/a09dc87e290c0497db65c4c702b37c2f

Kevin Buzzard (Apr 20 2018 at 17:47):

Just to be clear: my problem is that I need to prove something in term mode because it's part of a definition. Type class inference fails me and I don't know why. In tactic mode I can make type class inference succeed.

Kevin Buzzard (Apr 20 2018 at 17:47):

I could go down the awful route of adding @s and explicitly chasing up the proof, but I would rather let type class inference do its job properly and just add hints.

Simon Hudon (Apr 20 2018 at 17:48):

if it's a proof (i.e. it's type is a Prop) I think you can use a tactic:

to_fun :=
have local_proof : something, by ...,
definition_using_local_proof,

Simon Hudon (Apr 20 2018 at 17:55):

To my memory, local_proof gets compiled to an auxiliary definition / lemma and you'll have to_fun := definition_using_local_proof with a reference to that auxiliary definition (which will not be displayed because of proof erasure).

Kevin Buzzard (Apr 20 2018 at 18:03):

Unfortunately this fails, because my local proof is not a proof of the correct thing.

Kevin Buzzard (Apr 20 2018 at 18:03):

My local proof is a proof of the second monstrous expression in the gist, which can be proved by type class inference.

Kevin Buzzard (Apr 20 2018 at 18:03):

I have two maps phi and psi

Kevin Buzzard (Apr 20 2018 at 18:04):

and I can prove is_ring_hom (phi comp psi) with apply_instance

Kevin Buzzard (Apr 20 2018 at 18:04):

but when I write foo (phi comp psi)

Kevin Buzzard (Apr 20 2018 at 18:04):

for some function foo which needs (phi comp psi) to be a ring hom

Kevin Buzzard (Apr 20 2018 at 18:04):

then type class inference fails

Kevin Buzzard (Apr 20 2018 at 18:05):

well, this is my understanding of the situation.

Kevin Buzzard (Apr 20 2018 at 18:05):

I tried to create a MWE but I could not reproduce the problem in a controlled environment

Simon Hudon (Apr 20 2018 at 18:06):

What do you know about phi comp psi that makes it a is_ring_hom? Could you create:

instance [... some context about (phi comp psi) ...] : is_ring_hom (phi comp psi) := ...

right before the structure you're trying to define?

Johan Commelin (Apr 20 2018 at 18:07):

phi and psi are both ring homs themselves, if I understand Kevin correctly

Kevin Buzzard (Apr 20 2018 at 18:09):

Type class inference will make it a ring hom

Kevin Buzzard (Apr 20 2018 at 18:10):

Here is a very clear explanation of the situation I find myself in:

Kevin Buzzard (Apr 20 2018 at 18:10):

  to_fun := have XXX : is_ring_hom
    (of_comm_ring (away f) (powers (of_comm_ring R (powers f) g))  (of_comm_ring R (powers f)) )
    := by apply_instance,
  away.extend_map_of_im_unit
              (of_comm_ring (away f) (powers (of_comm_ring R (powers f) g))  (of_comm_ring R (powers f)))
              sorry,

Kevin Buzzard (Apr 20 2018 at 18:10):

(the sorry at the end is just to save you from having to look at another term)

Kevin Buzzard (Apr 20 2018 at 18:10):

So this definition fails

Kevin Buzzard (Apr 20 2018 at 18:10):

there's a red squiggle under away

Kevin Buzzard (Apr 20 2018 at 18:11):

and the error is

Kevin Buzzard (Apr 20 2018 at 18:11):

failed to synthesize type class instance for
R : Type u,
_inst_1 : comm_ring R,
f g : R,
H : Spec.D' g  Spec.D' f,
XXX : is_ring_hom (of_comm_ring (away f) (powers (of_comm_ring R (powers f) g))  of_comm_ring R (powers f))
 is_ring_hom (of_comm_ring (away f) (powers (of_comm_ring R (powers f) g))  of_comm_ring R (powers f))

Kevin Buzzard (Apr 20 2018 at 18:11):

Note that the goal looks exactly like XXX

Kevin Buzzard (Apr 20 2018 at 18:11):

and what is even more frustrating is that the goal and XXX were both created in the same way

Kevin Buzzard (Apr 20 2018 at 18:12):

by typing the same string twice

Kevin Buzzard (Apr 20 2018 at 18:12):

namely the string which appears in the goal

Kevin Buzzard (Apr 20 2018 at 18:12):

however if I set pp.all true

Kevin Buzzard (Apr 20 2018 at 18:12):

then XXX and the goal expand into the two distinct, but defeq, monsters

Kevin Buzzard (Apr 20 2018 at 18:13):

and note that XXX was proved by type class inference

Kevin Buzzard (Apr 20 2018 at 18:14):

What I need to understand to proceed, I think, is that I'd like to understand how Lean can unfold the same string in two different ways in these two situations.

Kevin Buzzard (Apr 20 2018 at 18:14):

I am scared to use a let to define the function, because I am scared it will cause me problems further down the line

Kevin Buzzard (Apr 20 2018 at 18:15):

I am trying to prove that a map is a bijection and if I do something screwy when defining the map then I'm worried I won't be able to use it later

Simon Hudon (Apr 20 2018 at 18:16):

The problem might be in the two terms that are defeq but not identical. Cosmetic differences in the syntax can take the instance inference process in a different direction. Do you think you can make them exactly identical?

Kevin Buzzard (Apr 20 2018 at 18:16):

this is exactly what I cannot do

Kevin Buzzard (Apr 20 2018 at 18:17):

because as you can see from my term

Kevin Buzzard (Apr 20 2018 at 18:17):

I created XXX and the input to away.extend_map_of_im_unit by typing exactly the same string of characters.

Simon Hudon (Apr 20 2018 at 18:18):

including the @?

Kevin Buzzard (Apr 20 2018 at 18:18):

aah I see

Kevin Buzzard (Apr 20 2018 at 18:18):

I can try to be more persuasive

Simon Hudon (Apr 20 2018 at 18:19):

It will probably not be concise but we can work on that once we know it works

Kevin Buzzard (Apr 20 2018 at 18:19):

by the way, am I right in thinking that I should not be using let in a defintion of a map?

Kevin Buzzard (Apr 20 2018 at 18:20):

Many thanks Simon

Kevin Buzzard (Apr 20 2018 at 18:20):

Explicitly telling Lean what the type of the composition was has solved the problem

Kevin Buzzard (Apr 20 2018 at 18:21):

Thanks a lot for persevering with this very awkward problem which was completely blocking me.

Kevin Buzzard (Apr 20 2018 at 18:21):

Many thanks indeed.

Simon Hudon (Apr 20 2018 at 18:22):

You're very welcome :)

Simon Hudon (Apr 20 2018 at 18:24):

by the way, am I right in thinking that I should not be using let in a defintion of a map?

I would avoid it especially if you're going to prove stuff about it. Maybe you're asking about the ùmathlibù style though. I haven't seen that mentioned anywhere but facilitating proofs using your definitions is likely to make you popular with the mathlib team.

Mario Carneiro (Apr 20 2018 at 23:12):

Have you tried using by exact in your definition? There is nothing wrong with using tactics in the definition of a term, although you may need to be more conscientious about junk added to your term by lean (or use by clean)

Mario Carneiro (Apr 20 2018 at 23:13):

there is not a problem with using let or other techniques in defining a complicated function, although you will probably want to write simp lemmas providing your interface so you don't need to rely on definitional expansion

Kevin Buzzard (Apr 21 2018 at 20:34):

Gaargh I have another one. Here's a MWE.

Kevin Buzzard (Apr 21 2018 at 20:34):

import algebra.ring
universes u v w uu

structure is_unique_R_alg_hom {R : Type u} {α : Type v} {β : Type w} [comm_ring R] [comm_ring α] [comm_ring β]
( : R  α) ( : R  β) (f : α  β) [is_ring_hom ] [is_ring_hom ] [is_ring_hom f] :=
(R_alg_hom :  = f  )
(is_unique :  g : α  β, is_ring_hom g   = g    g = f)

lemma comp_unique {R : Type u} {α : Type v} {β : Type w} {γ : Type uu}
  [comm_ring R] [comm_ring α] [comm_ring β] [comm_ring γ]
  ( : R  α) ( : R  β) ( : R  γ) (f : α  β) (g : β  γ) (h : α  γ)
  [is_ring_hom ] [is_ring_hom ] [is_ring_hom ] [is_ring_hom f] [is_ring_hom g] [is_ring_hom h] :
  is_unique_R_alg_hom   f  is_unique_R_alg_hom   g  is_unique_R_alg_hom   h  g  f = h :=
λ Uf Ug Uh, Uh.is_unique (g  f : α  γ) (by apply_instance) (by simp [Uf.R_alg_hom,Ug.R_alg_hom])

Kevin Buzzard (Apr 21 2018 at 20:34):

Note the by apply_instance on the last line!

Kevin Buzzard (Apr 21 2018 at 20:35):

If I replace that with _ then I get

Kevin Buzzard (Apr 21 2018 at 20:35):

don't know how to synthesize placeholder
context:
R : Type u,
α : Type v,
β : Type w,
γ : Type uu,
_inst_1 : comm_ring R,
_inst_2 : comm_ring α,
_inst_3 : comm_ring β,
_inst_4 : comm_ring γ,
sα : R → α,
sβ : R → β,
sγ : R → γ,
f : α → β,
g : β → γ,
h : α → γ,
_inst_5 : is_ring_hom sα,
_inst_6 : is_ring_hom sβ,
_inst_7 : is_ring_hom sγ,
_inst_8 : is_ring_hom f,
_inst_9 : is_ring_hom g,
_inst_10 : is_ring_hom h,
Uf : is_unique_R_alg_hom sα sβ f,
Ug : is_unique_R_alg_hom sβ sγ g,
Uh : is_unique_R_alg_hom sα sγ h
⊢ is_ring_hom (g ∘ f)

Kevin Buzzard (Apr 21 2018 at 20:35):

How does type class inference work? Is _ something other than by apply_instance?

Mario Carneiro (Apr 21 2018 at 20:37):

yes

Kevin Buzzard (Apr 21 2018 at 20:38):

I guess I just proved that :-)

Mario Carneiro (Apr 21 2018 at 20:38):

_ only does unification

Mario Carneiro (Apr 21 2018 at 20:38):

when it is omitted and the binder type is [tc A] it uses typeclass inference

Patrick Massot (Apr 21 2018 at 20:38):

You need is_unique_R_alg_hom.is_unique to take a square bracket argument

Mario Carneiro (Apr 21 2018 at 20:38):

by apply_instance does the same thing but manually

Kevin Buzzard (Apr 21 2018 at 20:39):

So "don't know how to synthesize placeholder" -- what did it try??

Mario Carneiro (Apr 21 2018 at 20:39):

unification

Mario Carneiro (Apr 21 2018 at 20:39):

and nothing else

Kevin Buzzard (Apr 21 2018 at 20:39):

I don't know what unification means

Kevin Buzzard (Apr 21 2018 at 20:40):

isn't that something to do with finding something of the right type?

Kevin Buzzard (Apr 21 2018 at 20:40):

Oh

Kevin Buzzard (Apr 21 2018 at 20:40):

I remember

Kevin Buzzard (Apr 21 2018 at 20:40):

it means "I will call this ?m_6"

Kevin Buzzard (Apr 21 2018 at 20:40):

"and sort it out later"

Kevin Buzzard (Apr 21 2018 at 20:41):

Thanks Patrick:

Kevin Buzzard (Apr 21 2018 at 20:41):

structure is_unique_R_alg_hom {R : Type u} {α : Type v} {β : Type w} [comm_ring R] [comm_ring α] [comm_ring β]
( : R  α) ( : R  β) (f : α  β) [is_ring_hom ] [is_ring_hom ] [is_ring_hom f] :=
(R_alg_hom :  = f  )
(is_unique : Π (g : α  β) [is_ring_hom g],  = g    g = f)

lemma comp_unique {R : Type u} {α : Type v} {β : Type w} {γ : Type uu}
  [comm_ring R] [comm_ring α] [comm_ring β] [comm_ring γ]
  ( : R  α) ( : R  β) ( : R  γ) (f : α  β) (g : β  γ) (h : α  γ)
  [is_ring_hom ] [is_ring_hom ] [is_ring_hom ] [is_ring_hom f] [is_ring_hom g] [is_ring_hom h] :
  is_unique_R_alg_hom   f  is_unique_R_alg_hom   g  is_unique_R_alg_hom   h  g  f = h :=
λ Uf Ug Uh, Uh.is_unique (g  f : α  γ) (by simp [Uf.R_alg_hom,Ug.R_alg_hom])

Patrick Massot (Apr 21 2018 at 20:42):

You're welcome

Kevin Buzzard (Apr 21 2018 at 20:43):

I have abstracted a standard trick :-)

Kevin Buzzard (Apr 21 2018 at 20:44):

I see, I was not even asking type class inference to do its job here. So this one is my bad.

Patrick Massot (Apr 21 2018 at 20:44):

Indeed

Kevin Buzzard (Apr 21 2018 at 23:15):

How do I do this one:

Kevin Buzzard (Apr 21 2018 at 23:15):

structure foo :=
(bar :  (α : Type) [group α] (a b c : α), Prop)

definition X : foo :=
{bar := λ α  a b c, (mul_assoc a b c)}

Kevin Buzzard (Apr 21 2018 at 23:20):

Can I use type class inference here?

Kenny Lau (Apr 21 2018 at 23:21):

you need a prop

Kenny Lau (Apr 21 2018 at 23:21):

that isn't a prop

Kenny Lau (Apr 21 2018 at 23:22):

structure foo :=
(bar :  (α : Type) [group α] (a b c : α), Prop)

definition X : foo :=
{bar := λ g Hg a b c, by letI := Hg; from mul_assoc a b c}

Kenny Lau (Apr 21 2018 at 23:22):

invalid type ascription, term has type
  a * b * c = a * (b * c) : Prop
but is expected to have type
  Prop : Type
state:
g : Type,
Hg : group g,
a b c : g,
_inst : group g := Hg
 Prop

Kevin Buzzard (Apr 21 2018 at 23:23):

I have some type mismatch error, I think I have more than one problem here

Kenny Lau (Apr 21 2018 at 23:25):

which is?

Kenny Lau (Apr 21 2018 at 23:25):

structure foo :=
(bar :  (α : Type) [group α] (a b c : α), Prop)

definition X : foo :=
{ bar := λ g Hg a b c, @mul_assoc _
    (@monoid.to_semigroup g $ @group.to_monoid g Hg) a b c }

Kevin Buzzard (Apr 21 2018 at 23:30):

mul_assoc a b c isn't a prop, it's a proof.

Kevin Buzzard (Apr 21 2018 at 23:30):

I know I can do it using @, I want to do it using type class inference

Kevin Buzzard (Apr 21 2018 at 23:30):

I want to understand how to make type class inference work, not to understand how to work around it (which I already know)

Kevin Buzzard (Apr 21 2018 at 23:31):

structure foo :=
(bar :  (α : Type) [group α] (a : α), 1 * a = a)

definition X : foo :=
{bar := λ α  a, group.one_mul a}

Kevin Buzzard (Apr 21 2018 at 23:31):

failed to synthesize type class instance for
α : Type,
Hα : group α,
a : α
⊢ group α

Kenny Lau (Apr 21 2018 at 23:31):

then just letI

Kevin Buzzard (Apr 21 2018 at 23:32):

Where do I put the letI?

Kevin Buzzard (Apr 21 2018 at 23:32):

I am in the middle of a structure

Kenny Lau (Apr 21 2018 at 23:32):

by letI := H\a; from group.one_mul a

Kevin Buzzard (Apr 21 2018 at 23:32):

What if I don't want to go into tactic mode because I am actually defining something?

Kevin Buzzard (Apr 21 2018 at 23:33):

What exactly are yuo suggesting?

Kevin Buzzard (Apr 21 2018 at 23:34):

definition X : foo :=
{bar := λ α  a, by letI := ; from group.one_mul a}

Kevin Buzzard (Apr 21 2018 at 23:34):

?

Kenny Lau (Apr 21 2018 at 23:34):

yes

Kevin Buzzard (Apr 21 2018 at 23:34):

7 errors

Kevin Buzzard (Apr 21 2018 at 23:34):

including "unknown identifier letI"

Kevin Buzzard (Apr 21 2018 at 23:35):

But even if we can get this to work

Kenny Lau (Apr 21 2018 at 23:35):

import anything from mathlib

Kevin Buzzard (Apr 21 2018 at 23:35):

I would rather just make type class inference work.

Kenny Lau (Apr 21 2018 at 23:35):

import algebra.group

structure foo :=
(bar :  (α : Type) [group α] (a : α), 1 * a = a)

definition X : foo :=
{bar := λ α  a, by letI := ; from group.one_mul a}

#print X._proof_1

/-
theorem X._proof_1 : ∀ (α : Type) (Hα : group α) (a : α), 1 * a = a :=
λ (α : Type) (Hα : group α) (a : α), let _inst : group α := Hα in group.one_mul a
-/

Kevin Buzzard (Apr 21 2018 at 23:35):

?!

Kenny Lau (Apr 21 2018 at 23:36):

!?

Kevin Buzzard (Apr 21 2018 at 23:36):

which version of Lean are you using?

Kevin Buzzard (Apr 21 2018 at 23:36):

aah

Kevin Buzzard (Apr 21 2018 at 23:36):

I have no import

Kevin Buzzard (Apr 21 2018 at 23:37):

letI is some mathlib magic I guess

Kenny Lau (Apr 21 2018 at 23:37):

it is.

Kenny Lau (Apr 21 2018 at 23:37):

it is Mario's workaround of Leo's changes.

Kenny Lau (Apr 21 2018 at 23:37):

So it's in mathlib.

Kevin Buzzard (Apr 21 2018 at 23:37):

Well thank you for your answer, which kind of stinks

Kevin Buzzard (Apr 21 2018 at 23:38):

Your answer seems to indicate that [group \a] is useless in my structure

Kevin Buzzard (Apr 21 2018 at 23:38):

i.e. it didn't insert H\a into the type class inference system anyway

Kevin Buzzard (Apr 21 2018 at 23:39):

but wait a minute, isn't this what Patrick told me to do earlier?

Kenny Lau (Apr 21 2018 at 23:39):

only typeclasses before the colon are inserted

Kenny Lau (Apr 21 2018 at 23:39):

that is Leo's changes

Kevin Buzzard (Apr 21 2018 at 23:39):

I am writing another localization interface by the way

Kevin Buzzard (Apr 21 2018 at 23:39):

rewriting your universal properties

Kenny Lau (Apr 21 2018 at 23:39):

heh

Mario Carneiro (Apr 21 2018 at 23:52):

you don't need to use letI, by exactI is the right solution for this application

Kenny Lau (Apr 21 2018 at 23:54):

aha

Kevin Buzzard (Apr 22 2018 at 00:25):

https://github.com/kbuzzard/lean-stacks-project/blob/master/src/localization_UMP.lean

Kevin Buzzard (Apr 22 2018 at 00:26):

I have finally battled through all my typeclass inference issues.

Kevin Buzzard (Apr 22 2018 at 00:26):

Kenny, I wrote an even better interface for localization

Kevin Buzzard (Apr 22 2018 at 00:26):

I put all the stuff which makes up the universal properties into one structure

Kevin Buzzard (Apr 22 2018 at 00:27):

is_unique_R_alg_hom

Kevin Buzzard (Apr 22 2018 at 00:27):

Mario, it's not quite mathlib-ready, but one day this should probably be in mathlib in some form if localization is in

Kevin Buzzard (Apr 22 2018 at 00:27):

because this file makes the localization stuff usable without ever having to touch the quotient type itself

Kevin Buzzard (Apr 22 2018 at 00:28):

I know because I'm using localization all the time in my schemes work and this work is what led me to the formalisation and the instances in the file I just linked to

Kevin Buzzard (Apr 22 2018 at 00:28):

There's one more instance of the structure which is commonly used which we still have to fill in

Mario Carneiro (Apr 22 2018 at 00:37):

Shouldn't comp_unique read something like is_unique_R_alg_hom sα sβ f → is_unique_R_alg_hom sβ sγ g → is_unique_R_alg_hom sα sγ (g ∘ f)?

Mario Carneiro (Apr 22 2018 at 00:40):

by rw ←HR.symm

what?

Patrick Massot (Apr 22 2018 at 09:10):

Nice one!

Patrick Massot (Apr 22 2018 at 09:11):

Kevin, is there is reason why your file doesn't have open classical towards the top? You write classical. quite a lot

Kevin Buzzard (Apr 22 2018 at 09:32):

Shouldn't comp_unique read something like is_unique_R_alg_hom sα sβ f → is_unique_R_alg_hom sβ sγ g → is_unique_R_alg_hom sα sγ (g ∘ f)?

No. That's not even true in general. The standard use of the universal property to prove that certain maps are isomorphisms is via the following argument: "We are given maps X-> Y and Y -> X. The given map from X to Y is the only map X -> Y with a certain property (e.g. being an R-algebra map). The map given Y -> X is the only map Y -> X with a certain property. Composition of two maps with the property has the property. The identity map X -> X is the only map X -> X with the property. Hence X -> Y -> X is the identity map by comp_unique. Furthermore the identity map Y -> Y is the only map Y -> Y with the property. Hence Y -> X -> Y is also the identity. So X isomorphic to Y".

Kevin Buzzard (Apr 22 2018 at 09:35):

The reason your suggestion is not true is that there could be plenty of maps from A to C which don't factor through B.

Kevin Buzzard (Apr 22 2018 at 09:36):

I don't open classical because I typically don't open anything. I am very bad at namespaces in general. A whole bunch of my code is incorrectly sitting in the root namespace. The whole thing needs a clear-up.

Kevin Buzzard (Apr 22 2018 at 09:44):

by rw ←HR.symm

what?

ha ha. I think it was getting late at that point. This was kind of stupid. I had that composition of f and g was h, but needed to show forall x, f (g x) = h xand I felt that this should just be an application of a standard lemma but I couldn't find it. So I just wrote "lambda x, by rw (proof that f circ g = h)" a few times, but then something was the other way round so I switched it and then something else was the other way around so I had to switch it back

Kevin Buzzard (Apr 24 2018 at 16:50):

Shouldn't comp_unique read something like is_unique_R_alg_hom sα sβ f → is_unique_R_alg_hom sβ sγ g → is_unique_R_alg_hom sα sγ (g ∘ f)?

Maybe you'll like this one:

Kevin Buzzard (Apr 24 2018 at 16:51):

theorem unique_R_of_unique_R_of_unique_Rloc {R : Type u} {α : Type v} {β : Type w} {γ : Type uu}
[comm_ring R] [comm_ring α] [comm_ring β] [comm_ring γ]
( : R  α) [is_ring_hom ] (fαβ : α  β) [is_ring_hom fαβ] (fβγ : β  γ) [is_ring_hom fβγ] :
is_unique_R_alg_hom  (fβγ  fαβ  ) (fβγ  fαβ)
 is_unique_R_alg_hom fαβ (fβγ  fαβ) fβγ
 is_unique_R_alg_hom (fαβ  ) (fβγ   fαβ  ) (fβγ) :=

Kevin Buzzard (Apr 24 2018 at 16:52):

If there's a unique R-alg hom from alpha to gamma and a unique alpha-alg hom from beta to gamma then there's a unique R-alg hom from beta to gamma (and it's the same map)

Kevin Buzzard (Apr 24 2018 at 16:52):

(oh, the R-alg hom from alpha to gamma must be the composite of a given map alpha -> beta and our given alpha-alg map from beta to gamma)

Johan Commelin (Apr 24 2018 at 17:18):

This feels like you want to hit it with Yoneda and reduce it to some basic set-theoretic fact... But that is only instinct

Johan Commelin (Apr 24 2018 at 17:19):

You're looking at both R-alg-homs and alpha-alg-homs... so maybe it is not that straightforward actually

Kenny Lau (Apr 24 2018 at 17:19):

don't get him started on alpha

Johan Commelin (Apr 24 2018 at 17:19):

What do you mean?

Johan Commelin (Apr 24 2018 at 17:19):

There is alpha's everywhere in his code

Johan Commelin (Apr 24 2018 at 17:20):

I was actually surprised when I saw that

Kenny Lau (Apr 24 2018 at 17:20):

don't say "alpha" and any mathematical object in the same sentence in front of kevin buzzard

Johan Commelin (Apr 24 2018 at 17:20):

But he just did that himself!

Kenny Lau (Apr 24 2018 at 17:20):

it doesn't matter

Kevin Buzzard (Apr 24 2018 at 17:33):

Did you notice that when we were doing groups earlier I used alpha to be a group homomorphism just to wind up the CS folk?

Kevin Buzzard (Apr 24 2018 at 17:34):

alpha : G to H

Kevin Buzzard (Apr 24 2018 at 17:34):

The reason I am using alpha for a ring

Kevin Buzzard (Apr 24 2018 at 17:34):

is that the most important ring is called R

Kevin Buzzard (Apr 24 2018 at 17:34):

and then I needed three more

Kevin Buzzard (Apr 24 2018 at 17:34):

but I couldn't face S T U

Kevin Buzzard (Apr 24 2018 at 17:34):

so I thought alpha beta gamma was OK

Kevin Buzzard (Apr 24 2018 at 17:35):

begin
  intros Hαβ Hβγ,
  constructor,refl,
  intros gβγ Hgβγ H1,
  have Hαγ : fβγ  fαβ = gβγ  fαβ,
    exactI (Hαβ.is_unique (gβγ  fαβ) H1).symm,
  exactI Hβγ.is_unique gβγ Hαγ,
end

Kevin Buzzard (Apr 24 2018 at 17:35):

That was the proof

Reid Barton (Apr 24 2018 at 17:40):

Haha, I seriously thought up to now that an "alpha-alg-hom" was a map of rings equipped with some fancy extra additional structure, like λ\lambda-rings or divided power rings or something.

Kevin Buzzard (Apr 24 2018 at 17:48):

no, it's an alpha-algebra hom :-)

Kevin Buzzard (Apr 24 2018 at 17:49):

YOU SEE YOU CS PEOPLE

Kevin Buzzard (Apr 24 2018 at 17:49):

THE MOMENT YOU CALL RINGS ALPHA

Kevin Buzzard (Apr 24 2018 at 17:49):

WE GET THINGS LIKE THIS HAPPENING

Johan Commelin (Apr 24 2018 at 17:50):

wow, that was pretty α-male

Kevin Buzzard (Apr 26 2018 at 22:54):

Here's today's type class inference issue:

Kevin Buzzard (Apr 26 2018 at 22:54):

theorem canonical_iso_is_canonical_hom {R : Type u} [comm_ring R] {f g : R} (H : Spec.D' g  Spec.D' f) :
let gbar := of_comm_ring R (powers f) g in
let  : R  loc (away f) (powers gbar) :=
  of_comm_ring (away f) (powers gbar)  of_comm_ring R (powers f) in
let  := (of_comm_ring R (non_zero_on_U (Spec.D' g))) in
let H2 := (canonical_iso H).is_ring_hom in
is_unique_R_alg_hom   (canonical_iso H).to_fun := sorry

Kevin Buzzard (Apr 26 2018 at 22:55):

that won't run

Kevin Buzzard (Apr 26 2018 at 22:55):

but hopefully I can explain the issue

Kevin Buzzard (Apr 26 2018 at 22:55):

I am trying to prove is_unique_R_alg_hom sγ sα (canonical_iso H).to_fun

Kevin Buzzard (Apr 26 2018 at 22:56):

but the definition of is_unique_R_alg_hom expects H2 to be deduced from type class inference

Kevin Buzzard (Apr 26 2018 at 22:56):

and I've only managed to prove it the line before

Kevin Buzzard (Apr 26 2018 at 22:56):

so I can solve this with @

Kevin Buzzard (Apr 26 2018 at 22:56):

but given that it would then look like

Kevin Buzzard (Apr 26 2018 at 22:58):

...erm

Kevin Buzzard (Apr 26 2018 at 22:58):

even that didn't work

Kevin Buzzard (Apr 26 2018 at 22:58):

@is_unique_R_alg_hom _ _ _ _ _ _ sγ sα (canonical_iso H).to_fun _ _ H2

Kevin Buzzard (Apr 26 2018 at 22:58):

actually it did work, I now have an unrelated problem

Kevin Buzzard (Apr 26 2018 at 22:59):

So can I insert H2 into the type class inference system before I have even started my proof, because I need it to make my term typecheck?

Kevin Buzzard (Apr 26 2018 at 23:09):

I have got it working with @

Kevin Buzzard (Apr 26 2018 at 23:09):

theorem canonical_iso_is_canonical_hom {R : Type u} [comm_ring R] {f g : R} (H : Spec.D' g  Spec.D' f) :
let gbar := of_comm_ring R (powers f) g in
let  : R  loc (away f) (powers gbar) :=
  of_comm_ring (away f) (powers gbar)  of_comm_ring R (powers f) in
let  := (of_comm_ring R (non_zero_on_U (Spec.D' g))) in
let H2 := (canonical_iso H).is_ring_hom in
let H3 : is_ring_hom  := by apply_instance in
let H4 : is_ring_hom  := by apply_instance in
@is_unique_R_alg_hom _ _ _ _ _ _   (canonical_iso H).to_fun H4 H3 H2 := sorry

Kevin Buzzard (Apr 26 2018 at 23:09):

The first three lets are simply there to make the statement look clearer

Kevin Buzzard (Apr 26 2018 at 23:10):

the last three are there because type class inference asked for them all

Reid Barton (Apr 26 2018 at 23:11):

Change those last three lets to letI I think

Kevin Buzzard (Apr 26 2018 at 23:12):

letI doesn't work there

Kevin Buzzard (Apr 26 2018 at 23:12):

well, it doesn't work for me

Kevin Buzzard (Apr 26 2018 at 23:12):

It works in a proof

Reid Barton (Apr 26 2018 at 23:12):

Sorry, I just noticed this was in term mode

Kevin Buzzard (Apr 26 2018 at 23:12):

but this is before the proof

Kevin Buzzard (Apr 26 2018 at 23:12):

the issue is that we're before the colon

Kevin Buzzard (Apr 26 2018 at 23:12):

I think

Reid Barton (Apr 26 2018 at 23:12):

But I think by letI ...; exact is fine

Kevin Buzzard (Apr 26 2018 at 23:12):

I have only seen letI after the colon

Reid Barton (Apr 26 2018 at 23:13):

Though, it does make me vaguely uneasy to put it in the theorem statement.

Reid Barton (Apr 26 2018 at 23:15):

theorem canonical_iso_is_canonical_hom {R : Type u} [comm_ring R] {f g : R} (H : Spec.D' g  Spec.D' f) :
let gbar := of_comm_ring R (powers f) g in
let  : R  loc (away f) (powers gbar) :=
  of_comm_ring (away f) (powers gbar)  of_comm_ring R (powers f) in
let  := (of_comm_ring R (non_zero_on_U (Spec.D' g))) in
by letI H2 := (canonical_iso H).is_ring_hom; exact
is_unique_R_alg_hom   (canonical_iso H).to_fun := sorry

(untested, hopefully I deleted the right amount of stuff)

Mario Carneiro (Apr 27 2018 at 00:39):

Using letI in theorem types is fine, and by letI ...; exact or by exactI is the recommended way to introduce a typeclass thing from the context in term mode

Chris Hughes (Apr 27 2018 at 06:43):

Don't use let in the statement of a theorem.

Kevin Buzzard (Apr 27 2018 at 06:51):

Don't use let in the statement of a theorem.

This is easy to fix -- the let is in some sense for my own sanity.

Mario Carneiro (Apr 27 2018 at 06:53):

Note that haveI when used in a tactic doesn't actually produce a have term, the result is just like you would get if it were actually inferred by regular tc inference

Mario Carneiro (Apr 27 2018 at 06:53):

If in doubt, just #print the statement to make sure it doesn't look weird

Kevin Buzzard (Apr 27 2018 at 06:53):

I can't get the syntax right for this

Kevin Buzzard (Apr 27 2018 at 06:53):

having tried for 10 seconds

Kevin Buzzard (Apr 27 2018 at 06:54):

I need to insert three hypotheses into the type class inference box

Kevin Buzzard (Apr 27 2018 at 06:54):

and I don't understand the syntax of this by thing

Kevin Buzzard (Apr 27 2018 at 06:55):

theorem canonical_iso_is_canonical_hom {R : Type u} [comm_ring R] {f g : R} (H : Spec.D' g  Spec.D' f) :
let gbar := of_comm_ring R (powers f) g in
let  : R  loc (away f) (powers gbar) :=
  of_comm_ring (away f) (powers gbar)  of_comm_ring R (powers f) in
let  := (of_comm_ring R (non_zero_on_U (Spec.D' g))) in
let H2 := (canonical_iso H).is_ring_hom in
let H3 : is_ring_hom  := by apply_instance in
let H4 : is_ring_hom  := by apply_instance in
@is_unique_R_alg_hom _ _ _ _ _ _   (canonical_iso H).to_fun H4 H3 H2 :=

Kevin Buzzard (Apr 27 2018 at 06:55):

This works

Kenny Lau (Apr 27 2018 at 06:55):

good luck proving that

Kevin Buzzard (Apr 27 2018 at 06:56):

begin
letI := (canonical_iso H).is_ring_hom,
have H5 := unique_R_alg_from_loc (canonical_iso H).to_fun,
have H6 := (canonical_iso H).R_alg_hom.symm,
simp [H6] at H5,
exact H5,
end

Kevin Buzzard (Apr 27 2018 at 06:56):

done

Kenny Lau (Apr 27 2018 at 06:56):

ok you win

Kevin Buzzard (Apr 27 2018 at 06:56):

Now I have good interface

Kevin Buzzard (Apr 27 2018 at 06:56):

so all the proofs are "this canonical thing is canonical"

Kevin Buzzard (Apr 27 2018 at 06:56):

or "this canonical thing is unique"

Kevin Buzzard (Apr 27 2018 at 06:57):

or "this unique thing is canonical"

Kevin Buzzard (Apr 27 2018 at 06:59):

I was trying to put all three hypotheses into one "by"

Kevin Buzzard (Apr 27 2018 at 06:59):

but I don't understand the syntax

Kevin Buzzard (Apr 27 2018 at 06:59):

but I've got it working

Kevin Buzzard (Apr 27 2018 at 06:59):

theorem canonical_iso_is_canonical_hom {R : Type u} [comm_ring R] {f g : R} (H : Spec.D' g  Spec.D' f) :
let gbar := of_comm_ring R (powers f) g in
let  : R  loc (away f) (powers gbar) :=
  of_comm_ring (away f) (powers gbar)  of_comm_ring R (powers f) in
let  := (of_comm_ring R (non_zero_on_U (Spec.D' g))) in
by letI H2 := (canonical_iso H).is_ring_hom; exact
by letI H3 : is_ring_hom  := by apply_instance; exact
by letI H4 : is_ring_hom  := by apply_instance; exact
@is_unique_R_alg_hom _ _ _ _ _ _   (canonical_iso H).to_fun H4 H3 H2 :=

Kevin Buzzard (Apr 27 2018 at 06:59):

I can't even parse that

Kevin Buzzard (Apr 27 2018 at 07:00):

and now the moment of truth...

Kevin Buzzard (Apr 27 2018 at 07:00):

wooah

Kevin Buzzard (Apr 27 2018 at 07:00):

stop everything

Kevin Buzzard (Apr 27 2018 at 07:00):

lean has silently crashed

Kevin Buzzard (Apr 27 2018 at 07:02):

OK great, when I restart Lean it just quietly exits

Kevin Buzzard (Apr 27 2018 at 07:03):

Restarting VS Code and I am back up and running

Kevin Buzzard (Apr 27 2018 at 07:04):

and it doesn't work after all

Kevin Buzzard (Apr 27 2018 at 07:06):

theorem canonical_iso_is_canonical_hom {R : Type u} [comm_ring R] {f g : R} (H : Spec.D' g  Spec.D' f) :
let gbar := of_comm_ring R (powers f) g in
let  : R  loc (away f) (powers gbar) :=
  of_comm_ring (away f) (powers gbar)  of_comm_ring R (powers f) in
let  := (of_comm_ring R (non_zero_on_U (Spec.D' g))) in
by letI H2 := (canonical_iso H).is_ring_hom;
letI H3 : is_ring_hom  := by apply_instance;
letI H4 : is_ring_hom  := by apply_instance; exact
@is_unique_R_alg_hom _ _ _ _ _ _   (canonical_iso H).to_fun H4 H3 H2 :=

doesn't work

Kevin Buzzard (Apr 27 2018 at 07:06):

It's not a problem because my multi-let @ solution works

Kevin Buzzard (Apr 27 2018 at 07:06):

I'll construct a MWE. I think this is just a syntax thing

Kevin Buzzard (Apr 27 2018 at 07:22):

gaargh it's not a syntax thing, my MWE is too minimal and strings of by letI ...; exact work fine

Kevin Buzzard (Apr 27 2018 at 07:27):

My by apply_instance proofs seem to be failing when wrapped up in the outer by

Kevin Buzzard (Apr 27 2018 at 07:33):

I am torn between giving up and constructing a MWE

Kenny Lau (Apr 27 2018 at 07:33):

lemme help you

Kenny Lau (Apr 27 2018 at 07:33):

give up.

Kevin Buzzard (Apr 27 2018 at 07:33):

OK

Kevin Buzzard (Apr 27 2018 at 07:33):

thanks

Kenny Lau (Apr 27 2018 at 07:33):

no probs

Mario Carneiro (Apr 27 2018 at 08:06):

Your letI : ... := by apply_instance lines are redundant. If the typeclass system can already find it, there's no reason to add it to the typeclass system. Unless you are trying to limit search depth?

Mario Carneiro (Apr 27 2018 at 08:07):

Also I recommend haveI over letI when possible. The only time you need letI is if you are unfolding the exact definition of the inferred ring or whatever later on in the same proof

Patrick Massot (Apr 27 2018 at 08:47):

About type classes, let me quickly share https://gist.github.com/PatrickMassot/0d28b74be6f7bc9c0814a87393c91663 It's a draft of documentation of something that took me an embarrassingly long time to understand (I don't say it's directly related to your issues, it's only general knowledge about type class magic)

Mario Carneiro (Apr 27 2018 at 08:50):

I think the ..prod.has_op on the last instance is unnecessary

Mario Carneiro (Apr 27 2018 at 08:51):

it is inferred if you don't specify

Patrick Massot (Apr 27 2018 at 08:52):

oooh

Patrick Massot (Apr 27 2018 at 08:52):

that's even better

Patrick Massot (Apr 27 2018 at 08:52):

How does this new magic trick work?

Patrick Massot (Apr 27 2018 at 08:52):

This file is all about understanding more magic

Mario Carneiro (Apr 27 2018 at 08:55):

The comm_magma.mk structure constructor has the to_has_op parent field as instance implicit, and in structure notation that translates to an optional field

Mario Carneiro (Apr 27 2018 at 08:56):

same with anonymous constructor notation, you could write it as just ⟨proof of commutativity⟩ instead of {op_comm := proof of commutativity}

Kevin Buzzard (Apr 28 2018 at 01:22):

Today's typeclass tale of woe:

Kevin Buzzard (Apr 28 2018 at 01:22):

import data.equiv
universes u v w u' v' w'
variables {α : Type u} {β : Type v} {γ : Type w} {α' : Type u'} {β' : Type v'} {γ' : Type w'}

structure canonically_isomorphic_add_group_homs ( : equiv α α') ( : equiv β β') (f : α  β) (f' : α'  β')
[add_group α] [add_group β] [add_group α'] [add_group β']
[is_group_hom f] [is_group_hom f']
:= sorry

Kevin Buzzard (Apr 28 2018 at 01:23):

failed to synthesize type class instance for
α : Type u,
β : Type v,
α' : Type u',
β' : Type v',
Cα : α ≃ α',
Cβ : β ≃ β',
f : α → β,
f' : α' → β',
_inst_1 : add_group α,
_inst_2 : add_group β,
_inst_3 : add_group α',
_inst_4 : add_group β',
_inst_5 : is_group_hom f
⊢ group β'

Kevin Buzzard (Apr 28 2018 at 01:29):

dammit

Kevin Buzzard (Apr 28 2018 at 01:29):

import data.equiv
universes u v w u' v' w'
variables {α : Type u} {β : Type v} {γ : Type w} {α' : Type u'} {β' : Type v'} {γ' : Type w'}

structure canonically_isomorphic_add_group_homs ( : equiv α α') ( : equiv β β') (f : α  β) (f' : α'  β')
[ : add_group α] [ : add_group β] [add_group α'] [Hβ' : add_group β']
[@is_group_hom α β  (by apply_instance) f] [@is_group_hom _ _ _ Hβ' f']
:= sorry

Kevin Buzzard (Apr 28 2018 at 01:30):

type mismatch at application
  is_group_hom
term
  Hα
has type
  add_group α
but is expected to have type
  group α

Kevin Buzzard (Apr 28 2018 at 01:30):

Damn you Lean

Kevin Buzzard (Apr 28 2018 at 01:30):

finding out how to turn an add_group to a group is exactly the kind of question which you should be good at.

Kevin Buzzard (Apr 28 2018 at 01:31):

thus saving me from having to remember the details about names of instances.

Kevin Buzzard (Apr 28 2018 at 01:32):

Why am I constantly running into type class inference issues @Sebastian Ullrich ? Is this sort of thing going to change in Lean 4, do you think?

Kevin Buzzard (Apr 28 2018 at 01:32):

I find the whole letI stuff both essential and extremely confusing

Kevin Buzzard (Apr 28 2018 at 01:32):

I probably need to write some letI docs

Kevin Buzzard (Apr 28 2018 at 01:33):

but am I right in thinking that letI is just a hack which we will be doing away with in Lean 4 as the amazing new type class inference system / syntax comes in?

Kevin Buzzard (Apr 28 2018 at 01:34):

I know that Mario has work hard to keep up with Leo's changes in the type class inference system

Kevin Buzzard (Apr 28 2018 at 01:34):

but that means that it's currently really confusing for end users

Kevin Buzzard (Apr 28 2018 at 01:35):

I believe in Lean so much

Kevin Buzzard (Apr 28 2018 at 01:35):

and I am really hoping for a beautiful solution.

Kevin Buzzard (Apr 28 2018 at 01:36):

Type class inference issues are stopping me from working right now.

Kevin Buzzard (Apr 28 2018 at 01:42):

variable (α : Type)
lemma to_group [H : add_group α] : group α := by apply_instance

Kevin Buzzard (Apr 28 2018 at 01:43):

tactic.mk_instance failed to generate instance for
  group α
state:
α : Type,
H : add_group α
⊢ group α

Sebastian Ullrich (Apr 28 2018 at 09:38):

There are no plans to change class inference for Lean 4. On the other hand, lifting the distinction between group and add_group is the primary motivation behind refactoring the algebraic hierarchy.

Kenny Lau (Apr 28 2018 at 09:38):

but the algebraic hierarchy also has its own problems, right

Kenny Lau (Apr 28 2018 at 09:39):

Today's typeclass tale of woe:

look, I already wrote you an is_add_group_hom

Kevin Buzzard (Apr 28 2018 at 13:48):

Oh, I see, I am an idiot. Lean regards the add_group hierarchy as completely different to, the group hierarchy. I have mixed my hierarchies without noticing

Kevin Buzzard (Apr 28 2018 at 13:48):

The reason I have made this mistake

Kevin Buzzard (Apr 28 2018 at 13:48):

is that the two heirarchies are canonically isomorphic

Kevin Buzzard (Apr 28 2018 at 13:48):

and indeed there is a unique canonical isomorphism in each direction

Kevin Buzzard (Apr 28 2018 at 13:49):

however the type class inference procedure might not use these canonical isomorphisms

Kevin Buzzard (Apr 28 2018 at 13:49):

because neither of the hierarchies is "better" than the other one

Kevin Buzzard (Apr 28 2018 at 13:49):

so it would be asymmetric to let type class inference move from one to the other

Kevin Buzzard (Apr 28 2018 at 13:50):

and there is a risk of diamonds if we let it move between them freely

Kevin Buzzard (Apr 28 2018 at 13:50):

On the other hand, to a mathematician, they are the same object

Kevin Buzzard (Apr 28 2018 at 13:50):

canonical isomorphism is different to type class resolution

Kevin Buzzard (Apr 28 2018 at 13:50):

and I was applying canonical isomorphism

Johan Commelin (Jun 15 2018 at 07:54):

Does this mean I introduced a diamond:

synthesized type class instance is not definitionally equal to expression inferred by typing rules, synthesized
subset.submodule 𝔥
inferred
lie_algebra.to_module ↥𝔥

Johan Commelin (Jun 15 2018 at 10:01):

So the context is as follows:

instance subset.lie_algebra {𝔥 : set 𝔤} [H : @is_lie_subalgebra R ri 𝔤 la 𝔥] :
lie_algebra R 𝔥 :=
{ bracket := λ x y, [x.1,y.1], is_lie_subalgebra.closed _ x.2 y.2,
  left_linear := begin
    intro y,
    constructor,
    { intros x₁ x₂,
      apply subtype.eq,
      simp,
      apply (lie_algebra.left_linear y).add, -- FAILS
      sorry },
    { intros r x,
      apply subtype.eq,
      -- apply (lie_algebra.left_linear y).smul, FAILS
      sorry }
  end,
  right_linear := sorry,
  alternating := assume x,_⟩, subtype.eq $ lie_algebra.alternating _,
  Jacobi_identity := assume x,_⟩ y,_⟩ z,_⟩, subtype.eq $ lie_algebra.Jacobi_identity _ _ _,
  anti_comm := assume x,_⟩ y,_⟩, subtype.eq $ lie_algebra.anti_comm _ _,
}

Johan Commelin (Jun 15 2018 at 10:02):

How do I tell Lean that it should infer subset.submodule 𝔥, instead of lie_algebra.to_module ↥𝔥.

Johan Commelin (Jun 15 2018 at 10:03):

I really don't get why the type class system is tripping up in this case. After all, the first instance unifies completely. The second instance has one meta-variable in it (and rightly so, because it can't infer that 𝔥 is a lie_algebra since that is exactly what I'm trying to prove.

Johan Commelin (Jun 15 2018 at 10:04):

So it seems to me like the type class inference went down a wrong path, but still got convinced that it did a good job. (While the correct path is actually there in Lean.)

Johan Commelin (Jun 15 2018 at 10:58):

Aaaahhrg.....

[class_instances]  class-instance resolution trace
[class_instances] (0) ?x_0 : has_bracket 𝔤 := @commutator_bracket ?x_1 ?x_2 ?x_3 ?x_4 ?x_5 ?x_6
[class_instances] (1) ?x_2 : comm_ring ?x_1 := ri
[class_instances] (1) ?x_4 : @lie_algebra R ?x_3 ri := la
[class_instances] (1) ?x_6 : ring 𝔤 := @nonneg_ring.to_ring ?x_7 ?x_8
[class_instances] (2) ?x_8 : nonneg_ring 𝔤 := @linear_nonneg_ring.to_nonneg_ring ?x_9 ?x_10
[class_instances] (1) ?x_6 : ring 𝔤 := @domain.to_ring ?x_7 ?x_8
[class_instances] (2) ?x_8 : domain 𝔤 := @linear_nonneg_ring.to_domain ?x_9 ?x_10
[class_instances] (2) ?x_8 : domain 𝔤 := @to_domain ?x_9 ?x_10
[class_instances] (3) ?x_10 : linear_ordered_ring 𝔤 := @linear_nonneg_ring.to_linear_ordered_ring ?x_11 ?x_12
[class_instances] (3) ?x_10 : linear_ordered_ring 𝔤 := @linear_ordered_field.to_linear_ordered_ring ?x_11 ?x_12
[class_instances] (4) ?x_12 : linear_ordered_field 𝔤 := @discrete_linear_ordered_field.to_linear_ordered_field ?x_13 ?x_14

[the list goes on and on...]

Johan Commelin (Jun 15 2018 at 10:59):

No stupid! It's a Lie algebra!

Johan Commelin (Jun 15 2018 at 10:59):

Everywhere in this file it has realised immediately that 𝔤 is a Lie algebra, and therefore has a bracket.

Johan Commelin (Jun 15 2018 at 10:59):

But somehow, here it messes up completely.

Andrew Ashworth (Jun 15 2018 at 11:10):

I notice type class inference issues are quite common in this chat. Maybe in the future a visualization aide would be helpful for people trying to debug the process

Andrew Ashworth (Jun 15 2018 at 11:11):

Actually for myself I don't know any better method to debug it than to write out the expression in full, and then in order work forwards as if I was doing the search by hand...

Johan Commelin (Jun 15 2018 at 11:12):

Right... which is not really what you would expect in this "computer-era"

Andrew Ashworth (Jun 15 2018 at 11:21):

you'd be disappointed in how much paper I go through while using a computerized theorem prover... or programming in general

Mario Carneiro (Jun 15 2018 at 11:23):

I have mentioned this in previous instance issues, but comm_ring ?x_1 is a bad sign in an instance trace, that will usually run away

Mario Carneiro (Jun 15 2018 at 11:23):

what is the type of commutator_bracket?

Johan Commelin (Jun 15 2018 at 11:39):

variables {S : Type*} [ring S]
instance commutator_bracket : has_bracket S := ⟨λ x y, x*y - y*x

Mario Carneiro (Jun 15 2018 at 11:41):

That can't be right, the printout has six variables not two

Mario Carneiro (Jun 15 2018 at 11:42):

what does #print commutator_bracket show?

Johan Commelin (Jun 15 2018 at 11:42):

Anyway, my point is that 𝔤 is a Lie algebra, and by definition that means it extends has_bracket. So I would hope that Lean could figure this one out.

Johan Commelin (Jun 15 2018 at 11:42):

@[instance]
protected def commutator_bracket : Π {R : Type u_1} [ri : comm_ring R] {𝔤 : Type u_2} [la : lie_algebra R 𝔤] {S : Type u_3} [_inst_1 : ring S],
  has_bracket S :=
λ {R : Type u_1} [ri : comm_ring R] {𝔤 : Type u_2} [la : lie_algebra R 𝔤] {S : Type u_3} [_inst_1 : ring S],
  {bracket := λ (x y : S), x * y - y * x}

Mario Carneiro (Jun 15 2018 at 11:42):

there's your problem

Johan Commelin (Jun 15 2018 at 11:42):

Which is crazy...

Johan Commelin (Jun 15 2018 at 11:43):

It pulls in way too much stuff.

Mario Carneiro (Jun 15 2018 at 11:43):

did you include stuff at the top maybe?

Mario Carneiro (Jun 15 2018 at 11:44):

try defining it outside the section, this instance has nothing to do with lie algebras

Johan Commelin (Jun 15 2018 at 11:45):

Yes... thanks for catching that!

Johan Commelin (Jun 15 2018 at 11:46):

Hmm, I need to run. In fact, I should try to get rid of those include ri la, but that seems to be non-trivial.

Johan Commelin (Jun 15 2018 at 11:47):

Anyway, I'll be back later. AFK

Kevin Buzzard (May 31 2019 at 19:04):

import algebra.punit_instances

-- works fine
example : add_comm_group unit := by apply_instance

class G_module (G : Type*) [group G] (M : Type*)
  extends add_comm_group M, has_scalar G M :=
(id :  m : M, (1 : G)  m = m)
(mul :  g h : G,  m : M, g  (h  m) = (g * h)  m)
(linear :  g : G,  m n : M, g  (m + n) = g  m + g  n)

example : add_comm_group unit := by apply_instance -- fails
/-
maximum class-instance resolution depth has been reached (the limit can be increased by setting option 'class.instance_max_depth') (the class-instance resolution trace can be visualized by setting option 'trace.class_instances')
state:
⊢ add_comm_group unit
-/

What did I do to deserve that? Is the class bad in some way?

Kevin Buzzard (May 31 2019 at 19:04):

set_option class.instance_max_depth 1000 doesn't fix it

Kevin Buzzard (May 31 2019 at 19:05):

[class_instances]  class-instance resolution trace
[class_instances] (0) ?x_0 : add_comm_group unit := @G_module.to_add_comm_group ?x_1 ?x_2 ?x_3 ?x_4
[class_instances] (1) ?x_2 : group ?x_1 := @subtype.group ?x_5 ?x_6 ?x_7 ?x_8
[class_instances] (2) ?x_6 : group ?x_5 := @subtype.group ?x_9 ?x_10 ?x_11 ?x_12
[class_instances] (3) ?x_10 : group ?x_9 := @subtype.group ?x_13 ?x_14 ?x_15 ?x_16
[class_instances] (4) ?x_14 : group ?x_13 := @subtype.group ?x_17 ?x_18 ?x_19 ?x_20
[class_instances] (5) ?x_18 : group ?x_17 := @subtype.group ?x_21 ?x_22 ?x_23 ?x_24
[class_instances] (6) ?x_22 : group ?x_21 := @subtype.group ?x_25 ?x_26 ?x_27 ?x_28
[class_instances] (7) ?x_26 : group ?x_25 := @subtype.group ?x_29 ?x_30 ?x_31 ?x_32
[class_instances] (8) ?x_30 : group ?x_29 := @subtype.group ?x_33 ?x_34 ?x_35 ?x_36
[class_instances] (9) ?x_34 : group ?x_33 := @subtype.group ?x_37 ?x_38 ?x_39 ?x_40
[class_instances] (10) ?x_38 : group ?x_37 := @subtype.group ?x_41 ?x_42 ?x_43 ?x_44
[class_instances] (11) ?x_42 : group ?x_41 := @subtype.group ?x_45 ?x_46 ?x_47 ?x_48
[class_instances] (12) ?x_46 : group ?x_45 := @subtype.group ?x_49 ?x_50 ?x_51 ?x_52
[class_instances] (13) ?x_50 : group ?x_49 := @subtype.group ?x_53 ?x_54 ?x_55 ?x_56
[class_instances] (14) ?x_54 : group ?x_53 := @subtype.group ?x_57 ?x_58 ?x_59 ?x_60
[class_instances] (15) ?x_58 : group ?x_57 := @subtype.group ?x_61 ?x_62 ?x_63 ?x_64
[class_instances] (16) ?x_62 : group ?x_61 := @subtype.group ?x_65 ?x_66 ?x_67 ?x_68
[class_instances] (17) ?x_66 : group ?x_65 := @subtype.group ?x_69 ?x_70 ?x_71 ?x_72
[class_instances] (18) ?x_70 : group ?x_69 := @subtype.group ?x_73 ?x_74 ?x_75 ?x_76
[class_instances] (19) ?x_74 : group ?x_73 := @subtype.group ?x_77 ?x_78 ?x_79 ?x_80
[class_instances] (20) ?x_78 : group ?x_77 := @subtype.group ?x_81 ?x_82 ?x_83 ?x_84
[class_instances] (21) ?x_82 : group ?x_81 := @subtype.group ?x_85 ?x_86 ?x_87 ?x_88
[class_instances] (22) ?x_86 : group ?x_85 := @subtype.group ?x_89 ?x_90 ?x_91 ?x_92
[class_instances] (23) ?x_90 : group ?x_89 := @subtype.group ?x_93 ?x_94 ?x_95 ?x_96
[class_instances] (24) ?x_94 : group ?x_93 := @subtype.group ?x_97 ?x_98 ?x_99 ?x_100
[class_instances] (25) ?x_98 : group ?x_97 := @subtype.group ?x_101 ?x_102 ?x_103 ?x_104
[class_instances] (26) ?x_102 : group ?x_101 := @subtype.group ?x_105 ?x_106 ?x_107 ?x_108
[class_instances] (27) ?x_106 : group ?x_105 := @subtype.group ?x_109 ?x_110 ?x_111 ?x_112
[class_instances] (28) ?x_110 : group ?x_109 := @subtype.group ?x_113 ?x_114 ?x_115 ?x_116
[class_instances] (29) ?x_114 : group ?x_113 := @subtype.group ?x_117 ?x_118 ?x_119 ?x_120
[class_instances] (30) ?x_118 : group ?x_117 := @subtype.group ?x_121 ?x_122 ?x_123 ?x_124
[class_instances] (31) ?x_122 : group ?x_121 := @subtype.group ?x_125 ?x_126 ?x_127 ?x_128
[class_instances] (32) ?x_126 : group ?x_125 := @subtype.group ?x_129 ?x_130 ?x_131 ?x_132

Kevin Buzzard (May 31 2019 at 19:06):

Can I solve this with some priority hack? Why does this happen?

Mario Carneiro (May 31 2019 at 19:07):

the class is bad, as you suspect

Floris van Doorn (May 31 2019 at 19:07):

Make add_comm_group M an argument of the class.

Mario Carneiro (May 31 2019 at 19:07):

and the offending instance is right there in the trace - G_module.to_add_comm_group

Floris van Doorn (May 31 2019 at 19:09):

something like

class G_module (G : Type*) (M : Type*) [group G] [add_comm_group M]
  extends has_scalar G M :=

Kevin Buzzard (May 31 2019 at 19:09):

That sounds like a really super instance though.

Kevin Buzzard (May 31 2019 at 19:10):

There is some subtlety here which I don't understand -- this is exactly one of those times where you're saying "don't do it this way, do it in some way which looks exactly the same to a mathematician". Is there some general principle I'm unaware of?

Mario Carneiro (May 31 2019 at 19:10):

Don't have a parent instance with fewer type arguments than the class

Kevin Buzzard (May 31 2019 at 19:11):

wait, what is a parent instance?

Mario Carneiro (May 31 2019 at 19:11):

extends produces an instance

Kevin Buzzard (May 31 2019 at 19:11):

And Floris' suggestion doesn't?

Mario Carneiro (May 31 2019 at 19:11):

In the original case it was [G_module G M] : add_comm_group M

Mario Carneiro (May 31 2019 at 19:12):

no, I am in complete agreement with floris

Mario Carneiro (May 31 2019 at 19:12):

floris is proposing to remove this instance, which is bad because G is "dangling"

Kevin Buzzard (May 31 2019 at 19:12):

Yes I understand that. And this is not generated in the suggested fix?

Kevin Buzzard (May 31 2019 at 19:13):

Sorry, I had a little internet time-out. My comment referred to "extends produces an instance"

Johan Commelin (May 31 2019 at 19:13):

@Kevin Buzzard You know about https://github.com/leanprover-community/mathlib/blob/66a86ffe010ffc32ee92e2e92cbdaf83487af168/src/group_theory/group_action.lean#L173 ?

Mario Carneiro (May 31 2019 at 19:13):

reading it from right to left, G just appears and lean doesn't know how to pick a value

Johan Commelin (May 31 2019 at 19:13):

/-- Typeclass for multiplicative actions on additive structures. This generalizes group modules. -/
class distrib_mul_action (α : Type u) (β : Type v) [monoid α] [add_monoid β] extends mul_action α β :=
(smul_add : (r : α) (x y : β), r  (x + y) = r  x + r  y)
(smul_zero {} : (r : α), r  (0 : β) = 0)

Kevin Buzzard (May 31 2019 at 19:15):

reading it from right to left, G just appears and lean doesn't know how to pick a value

I appreciate the problem; I am just saying that my understanding of why it occurs the way I did it and not the way Floris did it is hazy. extends produces an instance, this is the point. So Floris' method produces no instances?

Kevin Buzzard (May 31 2019 at 19:15):

Johan -- no, I didn't know about this.

Floris van Doorn (May 31 2019 at 19:15):

My solution doesn't generate the instance, because Lean will need to synthesize the instance add_comm_group M before it can even start searching for an instance of G_module G M

Kevin Buzzard (May 31 2019 at 19:15):

Right.

Mario Carneiro (May 31 2019 at 19:15):

there is still a parent instance coming from the other extends clause

Kevin Buzzard (May 31 2019 at 19:16):

In a parallel universe someone could tell me that this [Floris' suggestion] produces an instance anyway, and I would happily believe them.

Mario Carneiro (May 31 2019 at 19:17):

The easiest way to think of it is extends is notation for an extra field in the class + an instance to get to the parent from the child

Mario Carneiro (May 31 2019 at 19:18):

AFAIK it's the only way to get autogenerated instances

Floris van Doorn (May 31 2019 at 19:18):

Well, let's try do define this instance:

instance (G : Type*) (M : Type*) [group G] [add_comm_group M] [G_module G M] :
  add_comm_group M :=
_

What would you pick for the value of the underscore? It's the instance you already got as an argument. So this instance says "if you want add_comm_group M then you need to search for add_comm_group M (and a bunch more things). It's (worse than) useless.

Kevin Buzzard (May 31 2019 at 19:19):

My understanding of what is going on here is hazy at best. I even don't really understand, in some sense, why the instance is bad, because I don't really understand how type class inference works; I can of course see that it's bad because of what just happened, but the fact that I asked here instead of trying to fix it myself (which is nowadays my preferred solution with problems I run into) is just an indication of my poor understanding of this stuff.

I keep meaning to write some doc for docs/extras/ about the nitty-gritty of how type class inference works but I've had a busy year. The next three months are looking much nicer though, maybe I should actually do this; writing the docs myself will show me what I don't understand.

Mario Carneiro (May 31 2019 at 19:19):

It's a prolog-like search

Mario Carneiro (May 31 2019 at 19:22):

Every instance says "to prove A it suffices to prove B, C, D" and lean just applies all instances greedily hoping to get somewhere

Kevin Buzzard (May 31 2019 at 19:22):

[prolog] Yeah, somehow this is exactly the problem. I can believe that at some point in CS UG there's a chance to do some lectures / problem sets on how prolog works. In maths departments we don't do this. On a couple of occasions now I've sat down to fathom this out (even installing prolog on one occasion) but then never wrote down any of my thoughts and then I just forget them again. Writing things down is really helpful for me at my age -- only today did I look at my simp notes that I wrote so I could find out how to turn the trace on for simp -- I always forget, but I know where to look. The docs I write are "by me now, for me next week" :-)

Floris van Doorn (May 31 2019 at 19:22):

Btw, I don't have some magical superpower that I know how to do these things. The general strategy for a lot of formalization is to see if someone has done something similar before. If so, copy their code and adapt it to your case. In this case, the definition of module is similar:
https://github.com/leanprover-community/mathlib/blob/master/src/algebra/module.lean#L25
Often the design decisions will be the same for your case.

Kevin Buzzard (May 31 2019 at 19:23):

Btw, I don't have some magical superpower

Rotten luck! Mathematicians have a super-power.

Floris van Doorn (May 31 2019 at 19:23):

I do this all the time, even if I wrote the previous code. Past me was usually much more aware of all the pitfalls (because he fell into them, and then changed the code).

Kevin Buzzard (May 31 2019 at 19:23):

Unfortunately, Lean disables our super-power.

Mario Carneiro (May 31 2019 at 19:24):

You should mostly assume that lean applies instances in the worst possible order, because anything else is luck. So if there is an instance like "to prove T A it suffices to prove T (A x A)" then it should be clear that lean will loop

Kevin Buzzard (May 31 2019 at 19:24):

ha ha, that rule of thumb stinks! It's crying out for a fix.

Kevin Buzzard (May 31 2019 at 19:25):

The rule of thumb makes perfect sense, but somehow says "we could be doing this better". I guess we had this conversation once before quite recently.

Mario Carneiro (May 31 2019 at 19:25):

It's not as bad as it sounds; you just have to make sure that the worst possible order isn't that bad

Kevin Buzzard (May 31 2019 at 19:25):

I know that making typeclass inference better is on Leo's mind.

Floris van Doorn (May 31 2019 at 19:25):

i really think we should use priority n more in mathlib so that we can decide which instances should be applied first and which ones should be applied last.

Kevin Buzzard (May 31 2019 at 19:25):

[we had a brief email exchange when perfectoids got done, and he mentioned it]

Mario Carneiro (May 31 2019 at 19:26):

I agree that more use of priority would be a good thing, but I currently don't have a good model for how to structure the priorities

Floris van Doorn (May 31 2019 at 20:08):

My gut feeling says priorities should be as follows:

  • Structural instances: an instance which only works for certain types (like group A -> group B -> group (prod A B) or ring int). If such an instance applies, then it's almost always the instance you want to apply. So the order doesn't matter that much, but you can put the more common instances in front.
  • Forgetful instances, like comm_group A -> group A. Here you want to order them by how likely they are to apply (taking into consideration how long it would take for this instance to fail). Ultimately this will depend on which area of maths you're doing. When doing ring theory, you'll want to apply ring.to_add_comm_groupfirst, while in other cases you might want to do apply ordered_comm_group.to_add_comm_group first (this is not a great example, I think you almost always want to apply ring.to_add_comm_group first).

Looking a bit over #print instances, it looks like mathlib does this mostly right. I think this is partially accidental, since forgetful instances tend to be declared before structural instances are, and so even if they have the same priority they will be considered later. Some things I noticed:

  • Sometimes there are "shortcuts", like decidable_linear_ordered_comm_group.to_add_comm_group and ordered_comm_group.to_add_comm_group (or linear_ordered_ring.to_linear_order and linear_ordered_semiring.to_linear_order). If these instances do not apply, the search through the "order hierarchy" will happen twice, right? Probably these shortcuts should be removed?
  • nonneg_comm_group.to_add_comm_group should have a lower priority.
  • Some declarations should probably not be instances: decidable_eq_of_decidable_le or decidable_lt_of_decidable_le. Unfortunately they are in core...

Mario Carneiro (May 31 2019 at 20:11):

We need a real test to find out if shortcuts are taken twice

Floris van Doorn (May 31 2019 at 20:18):

Is set_option trace.class_instances true a reliable test?

example : add_comm_group bool := by apply_instance

gives

[...]
[class_instances] (0) ?x_0 : add_comm_group bool := @decidable_linear_ordered_comm_group.to_add_comm_group ?x_1 ?x_2
[class_instances] (1) ?x_2 : decidable_linear_ordered_comm_group bool := int.decidable_linear_ordered_comm_group
failed is_def_eq
[class_instances] (1) ?x_2 : decidable_linear_ordered_comm_group bool := @decidable_linear_ordered_comm_ring.to_decidable_linear_ordered_comm_group ?x_3 ?x_4
[class_instances] (2) ?x_4 : decidable_linear_ordered_comm_ring bool := @linear_nonneg_ring.to_decidable_linear_ordered_comm_ring ?x_5 ?x_6 ?x_7 ?x_8
[class_instances] (2) ?x_4 : decidable_linear_ordered_comm_ring bool := int.decidable_linear_ordered_comm_ring
failed is_def_eq
[class_instances] (2) ?x_4 : decidable_linear_ordered_comm_ring bool := @discrete_linear_ordered_field.to_decidable_linear_ordered_comm_ring ?x_5 ?x_6
[class_instances] (0) ?x_0 : add_comm_group bool := @ordered_comm_group.to_add_comm_group ?x_1 ?x_2
[...]
[class_instances] (4) ?x_8 : linear_ordered_comm_ring bool := @decidable_linear_ordered_comm_ring.to_linear_ordered_comm_ring ?x_9 ?x_10
[class_instances] (5) ?x_10 : decidable_linear_ordered_comm_ring bool := @linear_nonneg_ring.to_decidable_linear_ordered_comm_ring ?x_11 ?x_12 ?x_13 ?x_14
[class_instances] (5) ?x_10 : decidable_linear_ordered_comm_ring bool := int.decidable_linear_ordered_comm_ring
failed is_def_eq
[class_instances] (5) ?x_10 : decidable_linear_ordered_comm_ring bool := @discrete_linear_ordered_field.to_decidable_linear_ordered_comm_ring ?x_11 ?x_12
[class_instances] (1) ?x_2 : ordered_comm_group bool := @decidable_linear_ordered_comm_group.to_ordered_comm_group ?x_3 ?x_4
[class_instances] (2) ?x_4 : decidable_linear_ordered_comm_group bool := int.decidable_linear_ordered_comm_group
failed is_def_eq
[class_instances] (2) ?x_4 : decidable_linear_ordered_comm_group bool := @decidable_linear_ordered_comm_ring.to_decidable_linear_ordered_comm_group ?x_5 ?x_6
[class_instances] (3) ?x_6 : decidable_linear_ordered_comm_ring bool := @linear_nonneg_ring.to_decidable_linear_ordered_comm_ring ?x_7 ?x_8 ?x_9 ?x_10
[class_instances] (3) ?x_6 : decidable_linear_ordered_comm_ring bool := int.decidable_linear_ordered_comm_ring
failed is_def_eq
[class_instances] (3) ?x_6 : decidable_linear_ordered_comm_ring bool := @discrete_linear_ordered_field.to_decidable_linear_ordered_comm_ring ?x_7 ?x_8

It seems like it considered decidable_linear_ordered_comm_ring bool three times.

Floris van Doorn (May 31 2019 at 20:19):

Now sometimes duplication is impossible to avoid, without changing the code to the search, when you have diamonds...

Mario Carneiro (May 31 2019 at 20:23):

class A (α : Type) (n : )
class B (α : Type) (n : ) extends A α n
class C (α : Type) (n : ) extends B α n

instance C_nat : C  0 := @C.mk _ _ (@B.mk _ _ ⟨_, _⟩)

instance C_of_A' (α n) [A α n] : C α n.succ := @C.mk _ _ (@B.mk _ _ ⟨_, _⟩)
instance shortcut (α n) [C α n] : A α n := by apply_instance

set_option trace.class_instances true
set_option class.instance_max_depth 1000
#check (by apply_instance : C  30)

it's considering shortcut at each level but it's not exponential

Floris van Doorn (May 31 2019 at 20:25):

About the decidable_eq_of_decidable_leissue: maybe we should set their priorities in mathlib to 0, and decide that local attribute [instance, priority 10] classical.prop_decidable should happen at priority 10, not 0. Now, it probably searches through big chunks of the order hierarchy twice, when you want that prop_decidable should decide an equality on any type:

  • through decidable_linear_order α
  • through decidable_eq_of_decidable_le

Mario Carneiro (May 31 2019 at 20:25):

oh wait, C unit 7 is definitely exponential

Mario Carneiro (May 31 2019 at 20:25):

that's disconcerting

Mario Carneiro (May 31 2019 at 20:26):

once again I am staggered that typeclass inference works at all

Floris van Doorn (May 31 2019 at 20:27):

numerals have special support on nat, maybe that makes a difference?

Mario Carneiro (May 31 2019 at 20:27):

no, that just makes it a bit easier to write a bunch of succs here

Mario Carneiro (May 31 2019 at 20:28):

Compare the instance trace on C unit 7 with and without shortcut

Floris van Doorn (May 31 2019 at 20:28):

the problem is that your first instance never fails: all instances it tries succeed. Each branch is linear: backtracking is exponential.

Mario Carneiro (May 31 2019 at 20:30):

To some extent that's not unreasonable - I'm not sure how much we should care about failing searches

Floris van Doorn (May 31 2019 at 20:31):

a lot

Floris van Doorn (May 31 2019 at 20:31):

whenever you do local attribute [instance, priority 0] classical.prop_decidable there are a whole lot of failing searches.

Floris van Doorn (May 31 2019 at 20:31):

probably half of the "Forgetful instances" will fail. (even if applying another instance succeeds)

Mario Carneiro (May 31 2019 at 20:32):

here's a case where the instance succeeds but takes a long time:

class D (α : Type) (n : )
instance D_unit (n) : D unit n := ⟨_, _⟩
instance D_of_C (α n) [C α n] : D α n := ⟨_, _⟩

set_option trace.class_instances true
set_option class.instance_max_depth 1000
#check (by apply_instance : D unit 7)

Floris van Doorn (May 31 2019 at 20:38):

when doing some testing on my own

(message too long, truncated at 262144 characters)

lol,

But I think it's pretty clear we should remove these shortcuts of "forgetful" instances.

Mario Carneiro (May 31 2019 at 20:41):

this is a real shame, these could be useful in principle but lean really doesn't like them

Kevin Buzzard (May 31 2019 at 20:41):

(message too long, truncated at 262144 characters)

Gabriel put that check there precisely because I was fiddling around with this sort of thing once and managed to get a message that was so long that it broke stuff.

Mario Carneiro (May 31 2019 at 20:41):

but actually I don't know to what degree we can make our hierarchy "tree-like"

Mario Carneiro (May 31 2019 at 20:42):

algebraic hierarchies don't work like that

Floris van Doorn (May 31 2019 at 20:50):

There should really be a different algorithm for these "forgetful instances". Make a graph of all instances that change the class but not the type (like add_comm_group \a -> add_group \a) and when you have searched through all structural instances (or all instances with priority >= default priority), then use a graph reachability algorithm to quickly search for a path to any instance in the local context.

Kevin Buzzard (May 31 2019 at 21:36):

@Sebastian Ullrich how about you make type class search user-configurable? Everyone has different ideas :-)

Johan Commelin (Jun 01 2019 at 04:31):

I think that is one of the plans for Lean 4

Sebastian Ullrich (Jun 01 2019 at 17:33):

@Kevin Buzzard Making typeclass inference based on customizable tactics has been proposed before, but no one has figured out how to combine that with instance caching

Kevin Buzzard (Jun 01 2019 at 17:33):

My comment was really tongue-in-cheek I guess

Kevin Buzzard (Jun 01 2019 at 17:34):

The moment you let users do what they want is presumably the moment that things get really inefficient

Kevin Buzzard (Jun 01 2019 at 17:34):

We have seen type class inference doing some silly things recently

Kevin Buzzard (Jun 01 2019 at 17:35):

But it is not clear to me that there is some unified sensible algorithm which stops all of those silly things happening at once whilst remaining efficient

Kevin Buzzard (Jun 01 2019 at 17:35):

Why not just let prolog do it and make prolog a dependency?

Kevin Buzzard (Jun 01 2019 at 17:36):

Some people claimed that prolog was better than lean at prolog-like searches

Kevin Buzzard (Jun 01 2019 at 17:36):

I of course am in no position to comment

Johan Commelin (Jun 01 2019 at 17:37):

The difference is maybe that Prolog does a Prolog search, instead of merely a prolog-like search :grimacing:

Sebastian Ullrich (Jun 01 2019 at 17:38):

For starters, Lean's unification is much more complex than Prolog's. You wouldn't want to lose delta reduction in instance searches

Kevin Buzzard (Jun 01 2019 at 17:38):

I still reserve the right to snicker when Lean tries 20 random things in order to prove that rat has a one, before finally stumbling on rat.has_one

Johan Commelin (Jun 01 2019 at 17:39):

I still reserve the right to snicker when Lean tries 20 random things in order to prove that rat has a one, before finally stumbling on rat.has_one

:up: Completely agree. I think that guessing the correct name is one place where we could really win, and possibly win a lot.

Johan Commelin (Jun 01 2019 at 17:40):

For this reason, I've been trying to always use the auto-generated name for instances, in the hope that this will pay of in the future.

Sebastian Ullrich (Jun 01 2019 at 17:40):

This is one example where some instance indexing approach in Lean 4 should make the search instantaneous. Well, assuming you really have the same "one" in goal and instance.

Johan Commelin (Jun 01 2019 at 17:40):

It might break some sort of psychological/abstraction barrier in the software though: names ought to be irrelevant to Lean, and only relevant for humans.

Chris Hughes (Jun 01 2019 at 17:44):

Use some hidden name that isn't the name we have to look at.

Wojciech Nawrocki (Jul 11 2019 at 14:33):

Why does searching for instances in the local context work with explicit arguments but not under a lambda?

class myclass (α: Type)
def foo {α: Type} [myclass α] (a: α): α := a

def bar (n: ) [h: myclass ]:  :=
foo n -- good

def bar': Π (n: ) [myclass ],  :=
λ n h, foo n
/- failed to synthesize type class instance for
n : ℕ,
h : myclass ℕ
⊢ myclass ℕ -/

Chris Hughes (Jul 11 2019 at 14:35):

Performance reasons I think. You can do

def bar': Π (n: ) [myclass ],  :=
λ n h, by exactI foo n

or

def bar': Π (n: ) [myclass ],  :=
λ n h, by resetI; exact foo n

Wojciech Nawrocki (Jul 11 2019 at 14:38):

Ah indeed, local instances are "frozen". unfreeze_local_instances is the intrinsic for this. Thanks!


Last updated: Dec 20 2023 at 11:08 UTC