Can a class define a default superclass function?
It appears that it is not possible for a subclass to define a default for one of its superclass functions. In the example below, simply trying to declare the default method for (==) results in the error 'No member "==" in class "Pair"', which I think is consistent with [1]. But trying to include a signature for (==) in the specification of Pair results in a type error: Inferred type is not general enough *** Expression : eqPair *** Expected type : Pair a b c => a b c -> a b c -> Bool *** Inferred type : Pair a (b c d) (e f g) => a (b c d) (e f g) -> a (b c d) (e f g) -> Bool which also makes sense as (I assume) the new type signature for (==) is being picked up when using (==) to compare the component values. The closest I can see is to declare (say) eqPair as below, then define (==) = eqPair for each instance (as below). Is this a genuine restriction, or is there some way to avoid this? #g -- [1] http://haskell.org/onlinereport/decls.html#sect4.3.1 Example code: [[ -- Can a class define a default superclass method? class (Eq (a k v), Eq k, Eq v) => Pair a k v where newPair :: (k,v) -> a k v getPair :: a k v -> (k,v) eqPair :: a k v -> a k v -> Bool eqPair p1 p2 = (k1==k2) && (v1==v2) where (k1,v1) = (getPair p1) (k2,v2) = (getPair p2) -- or just: -- eqPair p1 p2 = (getPair p1) == (getPair p2) -- But can't say this: -- (==) :: a k v -> a k v -> Bool -- (==) = eqPair -- The simplest way I can see to define this is to define -- (==) per-instance using the default eqPair method of -- the Pair class, thus: newtype MyPair k v = P1 (k,v) instance (Eq k, Eq v) => Pair MyPair k v where newPair (x,y) = P1 (x,y) getPair (P1 (x,y)) = (x,y) instance (Eq k, Eq v) => Eq (MyPair k v) where (==) = eqPair ]] ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
In article <5.1.0.14.2.20030501153714.00b77c40@127.0.0.1>, Graham Klyne <gk@ninebynine.org> wrote:
It appears that it is not possible for a subclass to define a default for one of its superclass functions.
Correct. This is a common desire I think especially among people used to OOP, but there doesn't seem to be a clean way of doing it. For instance: module M where class C a where foo :: a -> a class (C a) => D a where foo = id instance C Char module N where import M instance D Char When compiling M, the compiler doesn't know instance D Char, so would presumably complain (warning) that foo is not defined in C and give it an undefined default. Perhaps it could work if it were a condition that instances of C and D be defined in the same module, and also if missing members in instances were errors rather than warnings (a good idea anyway IMO). -- Ashley Yakeley, Seattle WA
At 00:59 03/05/2003 -0700, Ashley Yakeley wrote:
In article <5.1.0.14.2.20030501153714.00b77c40@127.0.0.1>, Graham Klyne <gk@ninebynine.org> wrote:
It appears that it is not possible for a subclass to define a default for one of its superclass functions.
Correct. This is a common desire I think especially among people used to OOP, but there doesn't seem to be a clean way of doing it.
FWIW, I can live with this OK, using the device I mentioned previously. But I thought I might be missing something, which, in a sense, I was...
For instance:
module M where
class C a where foo :: a -> a
class (C a) => D a where foo = id
instance C Char
module N where import M
instance D Char
When compiling M, the compiler doesn't know instance D Char, so would presumably complain (warning) that foo is not defined in C and give it an undefined default.
Perhaps it could work if it were a condition that instances of C and D be defined in the same module, and also if missing members in instances were errors rather than warnings (a good idea anyway IMO).
... I hadn't fully appreciated that an instance declaration without a corresponding function definition would be OK. But maybe there's still a problem if one allows inheritance of function definitions: if the "instance C Char" indeed had a definition of "foo", then the definition of "foo :: Char -> Char" could vary in unexpected ways depending on which modules were imported? So, on reflection, it seems we have that being able to declare an *existing* data type as an instance (as opposed to OO style with static typing, where one typically must declare a new datatype to inherit from a supertype, I think), inheriting default definitions from a superclass can create undesired sensitivity to the visibility of module definitions. #g ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
participants (3)
-
Ashley Yakeley -
Graham Klyne -
Graham Klyne