
Ivan, It's the type of source and destination that is playing you parts. Let's write them explicitly quantified, source :: forall a b . (Packet a, Location b) => a -> b destination :: forall a b . (Packet a, Location b) => a -> b and reflect on this for a while. This basicly says that whenever I have a value of a type a that is known to be an instance of Packet, then for each type b that is known to be an instance of Location, source will give me an instance of that type b. (The same holds for destination, of course.) So now, I can define a new data type data Foo = Foo , declare it an instance of Location instance Location Foo where point foo = "foo" , and write the following function, knowing that TestPacket is an instance of Packet, getFoo :: Packet -> Foo getFoo packet = source packet . But, clearly, your implementation of source for TestPacket is not prepared to produce a value of Foo. Instead, it always produce a value of TestLocation. To be well-typed, however, it shoud be capable of producing a value of any type that is declared an instance of Location. A possible solution would be to fix the type of the returned location for each instance of Packet, class (Location b) => Packet a b where source, destination :: a -> b but this requires multi-parameter type classes, which are not part of Haskell 98. Another approach would be to enrich the interface of the Location class, so that it provides support for the construction of locations. HTH, Stefan