[Haskell-cafe] a simpler way to declare typeclass instances

Alexey Muranov alexey.muranov at gmail.com
Sat Oct 25 17:38:31 UTC 2014

Hello Adam,

On 25 oct. 2014, at 18:25, Adam Gundry <adam at well-typed.com> wrote:

> Hi Alexey,
> On 25/10/14 16:42, Alexey Muranov wrote:
>> i am trying to understand how typeclasses work.  I know that they can be used as follows (from the manual):
>>    data Foo = Foo {x :: Integer, str :: String}
>>    instance Eq Foo where
>>       (Foo x1 str1) == (Foo x2 str2) = (x1 == x2) && (str1 == str2)
>> I am wondering, why is the following seemingly unambiguous syntax not allowed too?
>>    data Foo = Foo { x :: Integer, str :: String }
>>    instance Eq Foo
>>    (Foo x1 str1) == (Foo x2 str2) = (x1 == x2) && (str1 == str2)
> This case is obviously unambiguous, but what is the general rule? Is the
> presence of the Foo data constructor important? What if I wrote the
> following, which would be a perfectly good instance method:
>    foo1 == foo2 = (x foo1 == x foo2) && (str foo1 == str foo2)
> In general, should the compiler be doing type inference to determine
> which instance a declaration belongs to? In principle, the language
> could permit instance methods to be detached from the instances
> themselves, but I don't think it should.

I have not really thought well about this, but i see no problem with your example: the compiler can use type inference to see that `foo1` and `foo2` are of type `Foo`.  I see that type inference is used everywhere in Haskell, back and forth and upside down [1], so why not here? :)

In fact, even the `instance Eq Foo` declaration should be unnecessary IMO because it can be inferred.

I imagine there could be other obstacles of which i haven't thought.

>> If it was allowed, it seems that it could also be applied to records:
>>    class HasName r where
>>        name :: r -> String
>>    data Bird   = Bird { name :: String, wingNumber :: Integer }
>>    data Person = Person { name :: String, likesBirds :: Bool }
>>    instance HasName Bird
>>    instance HasName Person
> Note that this currently would only work if you declare Bird and Person
> in different modules. I'm not convinced that saving one line of
> boilerplate in the instance declarations is worth it.

It is not to save one line but to avoid namespace pollution with record field names.  I do not see why Bird and Person would need to be in different modules if the compiler could determine that they both are instances of HasName.  Of course, currently this does not work. 

> On the topic of records in particular, you may be interested in the work
> on OverloadedRecordFields [1], which might (or might not) appear in GHC
> 7.10.
> Cheers,
> Adam
> [1] https://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields

Thanks for the link, i believe i've read something about it.  This looks a bit complicated for me, maybe i'll look at it again later.


[1] http://stackoverflow.com/questions/3467279/how-to-create-a-polyvariadic-haskell-function

More information about the Haskell-Cafe mailing list