a simpler way to declare typeclass instances

Hello, 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) 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 Alexey.

Well, in this case it would look like a definition of a completely independent function (=), which, obviously, clashes with the already defined one. In general, it's a good idea to keep things that don't make sense without some previous declaration inside the block, established by that declaration.
On 25 Oct 2014, at 19:42, Alexey Muranov
wrote: Hello,
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)
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
Alexey. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

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.
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. 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 -- Adam Gundry, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

Hello Adam,
On 25 oct. 2014, at 18:25, Adam Gundry
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. Alexey. [1] http://stackoverflow.com/questions/3467279/how-to-create-a-polyvariadic-hask...

On 25 oct. 2014, at 18:25, Adam Gundry
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.
Maybe to specify the types without type inference, something like this could be used: (foo1 :: Foo) == (foo2 :: Foo) = (x foo1 == x foo2) && (str foo1 == str foo2) Alexey. P.S. Maybe all i say is nonsense, I am not very familiar with the theory of types. I plan to read the Hindley's paper when i have time.
participants (3)
-
Adam Gundry
-
Alexey Muranov
-
MigMit