
G'day everyone. Suppose I have code like this: class Foo a b | a -> b where foo :: a -> b bar :: (Foo Char t) => t bar = foo 'a' All well and good so far. Let's add an instance of Foo... instance Foo Char Bool where foo c = isAlpha c Now neither GHC nor Hugs will allow this to compile, as the declared type of bar is "too general". This seems intuitively the wrong behaviour. Either the original program was incorrect (as there was no visible instance of Foo for type Char) or the amended program is correct (since the type of bar is no more general than it was in the first version). Thoughts? Cheers, Andrew Bromage

hello, Andrew J Bromage wrote:
G'day everyone.
Suppose I have code like this:
class Foo a b | a -> b where foo :: a -> b
bar :: (Foo Char t) => t bar = foo 'a'
All well and good so far. Let's add an instance of Foo...
instance Foo Char Bool where foo c = isAlpha c
Now neither GHC nor Hugs will allow this to compile, as the declared type of bar is "too general".
The declared type here refers to the signature of "bar". It says that bar should work for any "t", but the functional dependency forces "t" to be Bool.
This seems intuitively the wrong behaviour. Either the original program was incorrect (as there was no visible instance of Foo for type Char) or the amended program is correct (since the type of bar is no more general than it was in the first version).
In a sense the original program is wrong. The way I think of the declaration is as follows: "if there was an instance for 'Foo Char t' (for all t) I could make you a 't' as declared in the body of the function". Now since there is no instance for 'Foo Char t' you would never be able to use "bar", and in that sense the program is wrong (well, perhaps useless). An instance that would work with the declaration of "bar" would be somthing like: instance Foo [a] a where foo = head bye iavor

G'day all. On Mon, May 12, 2003 at 10:04:05AM -0700, Iavor Diatchki wrote:
The declared type here refers to the signature of "bar". It says that bar should work for any "t", but the functional dependency forces "t" to be Bool.
Actually, the functional dependency forces t to be _something_, but until you see the instance, you don't know what that something is.
In a sense the original program is wrong.
...and in a similar sense the final program is right. In the code which I cut this example down from, it's actually a more desirable type declaration, because rather than "Bool", the true return type of the function in question is a complex type generated using typeclass meta-programming which clients probably don't want to know about.
The way I think of the declaration is as follows: "if there was an instance for 'Foo Char t' (for all t) I could make you a 't' as declared in the body of the function". Now since there is no instance for 'Foo Char t' you would never be able to use "bar", and in that sense the program is wrong (well, perhaps useless).
True, in the original program, there is "no instance". However, this is just a cut-down illustration. To be useful, it is sufficient for the relevant instance of the Foo typeclass to be in scope for whoever calls "bar". Cheers, Andrew Bromage
participants (2)
-
Andrew J Bromage
-
Iavor Diatchki