
Think of it like this. Should this be acceptable? f :: a -> a -> a f x y = x && y No, because the type (forall a. a->a->a) is plainly more general than the actual function. The type tempts you to think that you could write f 3 4 but you can't. But I suppose you could argue that the function definition should be allowed, but if you ever called (f 3 4) you should get an error "Int found where Bool expected". Your signature is bar :: (Foo Char t) => t and we know (from the instance decl) that t must be Bool. Any other call to bar would be illegal, just as any cal to 'f' above is illegal, except at type Bool. In general, it seems to make sense to reject definitions as early as possible, hence GHC and Hugs reject it. It is undoubtedly odd that adding an instance declaration makes a legal program illegal, and that might be a reason for relaxing the rule... but it's not entirely easy to implement such a relaxation. Simon | -----Original Message----- | From: haskell-cafe-admin@haskell.org [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Andrew | J Bromage | Sent: 12 May 2003 06:10 | To: haskell-cafe@haskell.org | Subject: Functional dependencies question | | 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 | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe

G'day all. On Tue, May 13, 2003 at 08:58:35AM +0100, Simon Peyton-Jones wrote:
Think of it like this. Should this be acceptable?
f :: a -> a -> a f x y = x && y
No, because (&&) is not defined on anything but Bool.
Your signature is bar :: (Foo Char t) => t and we know (from the instance decl) that t must be Bool.
Even if we don't have the instance declaration, we know that t must be some unique type because of the fundep. (Of course that type may be polymorphic, which probably complicates things.)
It is undoubtedly odd that adding an instance declaration makes a legal program illegal, and that might be a reason for relaxing the rule... but it's not entirely easy to implement such a relaxation.
Understood, and I'm not so worried about it now that we've found a few ways to get around my motivating problem. BTW, even worse than adding an instance declaration making a legal program illegal is moving an instance declaration across a module boundary. GHC appears perfectly happy with this: << module Foo where class Foo a b | a -> b where foo :: a -> b bar :: (Foo Char t) => t bar = foo 'a'
<< module Bar where import Foo instance Foo Char Bool where foo a = a == 'a'
<< % ghci -fglasgow-exts Bar.hs [deletia] Ok, modules loaded: Bar, Foo. *Bar> :t bar bar :: Bool *Bar> bar True
Cheers, Andrew Bromage

hello, Simon Peyton-Jones wrote:
It is undoubtedly odd that adding an instance declaration makes a legal program illegal, and that might be a reason for relaxing the rule... but it's not entirely easy to implement such a relaxation.
this has always been the case, unless i am misunderstanding what you are saying. for exampel adding the instance: instance Show Int will make any valid program invalid bye iavor

Dnia wto 13. maja 2003 09:58, Simon Peyton-Jones napisaĆ:
Think of it like this. Should this be acceptable?
f :: a -> a -> a f x y = x && y
No, because the type (forall a. a->a->a) is plainly more general than the actual function.
It's not the same. The type doesn't constrain a by any class, so it would look like any type fits, which is not true.
bar :: (Foo Char t) => t
In this case the type seems OK: for any type t, *if* Foo Char t, then bar can be used as type t. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/
participants (4)
-
Andrew J Bromage
-
Iavor Diatchki
-
Marcin 'Qrczak' Kowalczyk
-
Simon Peyton-Jones