| 506 | |
| 507 | |
| 508 | ----------------------------------- |
| 509 | |
| 510 | == Counterfactuals == |
| 511 | |
| 512 | Arising from discussion, further modifications are worth considering, if only to step back from them. |
| 513 | |
| 514 | === Liberalization 7 Use type inference to disambiguate member distribution. === |
| 515 | |
| 516 | We could imagine permitting |
| 517 | {{{ |
| 518 | class Foo x where |
| 519 | foo :: x -> x |
| 520 | |
| 521 | class (instance Foo x, instance Foo y) => Goo x y where |
| 522 | goo :: x -> y |
| 523 | }}} |
| 524 | and if we saw |
| 525 | {{{ |
| 526 | instance Goo Int Bool where |
| 527 | foo x = 3 |
| 528 | foo x = True |
| 529 | goo = (0 <) |
| 530 | }}} |
| 531 | it would be obvious that we meant |
| 532 | {{{ |
| 533 | instance Foo Int where |
| 534 | foo x = 3 |
| 535 | instance Foo Bool where |
| 536 | foo x = True |
| 537 | instance Goo Int Bool where |
| 538 | goo = (0 <) |
| 539 | }}} |
| 540 | because type information tells us which `foo` belongs where. |
| 541 | |
| 542 | That is, we could adopt a policy of complaining only if type inference fails to disambiguate the distribution of members to internal instances. |
| 543 | |
| 544 | We might need enough notation to opt out of `Foo x` but not `Foo y`. More explicit notation will be necessary |
| 545 | whenever the given definitions. E.g., |
| 546 | {{{ |
| 547 | instance Goo Int Bool where |
| 548 | foo 0 = 3 |
| 549 | foo x = x |
| 550 | foo x = True |
| 551 | goo = (0 <) |
| 552 | }}} |
| 553 | does not establish in which instance the `foo x = x` line belongs. |
| 554 | |
| 555 | Of course, one could reject such programs as ambiguous, but certainly, the static semantics of such a system is far more subtle than the present proposal. |
| 556 | |
| 557 | === Liberalization 8 Make superclasses intrinsic by default. === |
| 558 | |
| 559 | We could drop the use of `instance` to mark which superclasses are intended as intrinsic. Again adopting a complain-on-ambiguity semantics, we could generate a superclass instance automatically from a subclass instance whenever there is at least one candidate member definition: either a default in the subclass, or an explicit definition in the subclass instance. So |
| 560 | {{{ |
| 561 | class Bing x where |
| 562 | bing :: x |
| 563 | class Bing x => Bong x where |
| 564 | bong :: x |
| 565 | instance Bong Int where |
| 566 | bing = 1 |
| 567 | bong = 0 |
| 568 | }}} |
| 569 | generates a `Bing Int` instance too, as does |
| 570 | {{{ |
| 571 | class Bing x where |
| 572 | bing :: x |
| 573 | class Bing x => Bong x where |
| 574 | bong :: x |
| 575 | bing = bong |
| 576 | instance Bong Int where |
| 577 | bong = 0 |
| 578 | }}} |
| 579 | but |
| 580 | {{{ |
| 581 | class Bing x where |
| 582 | bing :: x |
| 583 | class Bing x => Bong x where |
| 584 | bong :: x |
| 585 | instance Bong Int where |
| 586 | bong = 0 |
| 587 | }}} |
| 588 | generates only a `Bong Int` instance (rather than an empty `Bing Int` instance). |
| 589 | |
| 590 | Such a proposal would require a little more subtlety to determine which instances are generated, but might be sustainable. |
| 591 | |
| 592 | Certainly, it would still require authors of client code to be aware of whether a given class is likely to generate superclass instances. If I define some rather special purpose library with |
| 593 | {{{ |
| 594 | class Eq x => WhizzBanger x where |
| 595 | whizz :: x -> x -> x |
| 596 | bang :: x -> Bool |
| 597 | }}} |
| 598 | then clients need to know whether their `WhizzBanger` instances need to bring an `Eq` instance or will get one. This liberalization cuts the `instance` notation in class declarations but not the necessity to be aware of what it makes explicit. |