Zulip Chat Archive

Stream: new members

Topic: failed to synthesize type class instance decidable_pred


Henning Dieterichs (Nov 02 2020 at 11:30):

I have this function definition:

def test : list (nat × nat)  list (nat × nat)
| list := list.filter (λ  a, b ⟩, a > 10)

But I get the error

failed to synthesize type class instance for
test : _root_.list ( × )  _root_.list ( × ),
list : _root_.list ( × )
 decidable_pred (λ (_x :  × ), test._match_1 _x)

This works though:

def test : list (nat × nat)  list (nat × nat)
| list := list.filter (λ x, x.fst > 10)

Seems like destructuring is not very compatible with automatic inference of decidability?

Kevin Buzzard (Nov 02 2020 at 11:39):

You can see exactly the problem which occurs. Using λ ⟨ a, b ⟩ is fine for proving theorems, but causes problems when making definitions because of the way Lean 3 takes this apart internally. Stick to the bottom one.

Henning Dieterichs (Nov 02 2020 at 11:40):

Thanks! I'd love to use destructuring though, as fst and snd are not very speaking

Kevin Buzzard (Nov 02 2020 at 11:41):

There's x.1 and x.2 but I totally agree.

Jasmin Blanchette (Nov 02 2020 at 11:45):

fst and snd are the traditional ML names, probably from the 80s if not earlier. We could always switch to Lisp-style car and cdr. :smiley:

Kevin Lacker (Nov 02 2020 at 19:08):

I wonder, why exactly doesn't this destructuring work in this situation? it would be a lot more readable to use inline functions of product types with destructuring syntax. I don't quite understand what the failed to synthesize type class instance error means here

Kevin Buzzard (Nov 02 2020 at 19:09):

You can see what happens from the error I guess. Lean can't see through the test._match_1 and I'm not sure if we can get to it to mark it reducible.

Kevin Buzzard (Nov 02 2020 at 19:12):

I was writing code for undergraduates last week and I did find this really annoying -- I defined a map on nat^2 by f(x)=something involving x.1 and x.2, and then I immediately wrote a lemma saying that f((a,b)) was the same thing but involving a and b. At the time I thought it looked clunky but this is what people have been doing in the past. Until January there were many requests from users for which the answer was "we can't do anything about it, it's in core" but now we have control of core we can do more things. I have no idea whether we can do something about this though. I can't remember whether have people have thought about it seriously since January -- I think a lot of us are just resigned to the x.1, x.2 thing.

Kevin Lacker (Nov 02 2020 at 19:16):

this sort of destructuring also semi-recently got into javascript and it has been nice there

Mario Carneiro (Nov 02 2020 at 21:42):

The issue is that there is no decidable instance defined for test._match_1

Mario Carneiro (Nov 02 2020 at 21:43):

marking it reducible won't help, it's defined by cases and there is no decidable instance for foo.cases_on either

Kevin Lacker (Nov 02 2020 at 21:44):

why is it any different from calling the pair _x and referring to the parts as _x.1 and _x.2? to me it seems like you'd be able to deduce the same thing about either syntax, since they are logically identical

Mario Carneiro (Nov 02 2020 at 21:44):

this is slightly different from the problem of definitional equalities that explains why we usually avoid pattern matching definitions

Mario Carneiro (Nov 02 2020 at 21:45):

They are logically identical, but that doesn't mean that they have the same instances

Mario Carneiro (Nov 02 2020 at 21:45):

even defeq things can have different instances

Mario Carneiro (Nov 02 2020 at 21:46):

Normally, you would make a definition and then prove it's decidable. If you made test._match_1 into a proper definition that's what you would do, and then there would be no issue

Mario Carneiro (Nov 02 2020 at 21:46):

but for these on the spot definitions it's usually not worth the effort compared to a slight reformulation

Kevin Lacker (Nov 02 2020 at 21:47):

so the problem is that lean sees the pair, and it's like well who knows if a lambda on a pair is decidable, and then it fails because it does not know that a lambda on a pair is decidable when the lambda is decidable on each of the parts

Mario Carneiro (Nov 02 2020 at 21:48):

It doesn't see lambda on a pair at all, it sees a new definition

Reid Barton (Nov 02 2020 at 21:48):

Even if it could see through all the equation compiler stuff, it would still face the term x.cases_on (\lam a b, a < 10) rather than the term x.fst < 10

Mario Carneiro (Nov 02 2020 at 21:49):

There is some parser magic that means that \lam <x, y>, e is equivalent to pausing the current elaboration, writing def foo | <x, y> := e just above, and then inserting foo at the point of use

Mario Carneiro (Nov 02 2020 at 21:49):

Conceivably, we could have instances that prove things about decidability of a cases_on expression

Mario Carneiro (Nov 02 2020 at 21:50):

but it still requires some unfolding

Kevin Lacker (Nov 02 2020 at 21:51):

if the parser magic is inserting foo everywhere, why does it work differently for a human to put foo.1 and foo.2 throughout the expression? because there's an extra def this way?

Mario Carneiro (Nov 02 2020 at 21:51):

foo.1 and foo.2 don't make new definitions

Mario Carneiro (Nov 02 2020 at 21:51):

it's also literally a different expression as reid says

Mario Carneiro (Nov 02 2020 at 21:52):

it's the difference between x.cases_on (\lam a b, a < 10) and x.cases_on (\lam a b, a) < 10

Mario Carneiro (Nov 02 2020 at 21:52):

the second one is obviously decidable even if you don't know what cases_on does


Last updated: Dec 20 2023 at 11:08 UTC