
Ivan Tihonov wrote:
I start some ip networks related work in haskell and wrote two basic classes Location and Packet. Before writing IpLocation and IpPacket instances i have written simple TestLocation and TestPacket instances just to compile this and check for errors in class definitions. But looks like i misunderstand some haskell principles...
====================================================== class Location a where point :: a -> String
class Packet a where source, destination :: Location b => a -> b
This says that source can return any type which is an instance of Location. IOW, any instance of Packet can have any instance of Location as its source and destination (and can even use different instances of Location for the two functions).
data TestLocation = TestSource | TestDestination data TestPacket = TestPacket
instance Packet TestPacket where source p = TestSource
However, this definition of source has type: TestPacket -> TestLocation when, according to the class definition, it should have type: (Location b) => TestPacket -> b
ERROR Test.hs:20 - Inferred type is not general enough *** Expression : source *** Expected type : (Packet TestPacket, Location a) => TestPacket -> a *** Inferred type : (Packet TestPacket, Location TestLocation) => TestPacket -> TestLocation
Hence this error message; the function returns a specific instance of
Location, when it should return an arbitry instance.
You can use functional dependencies, which aren't in the Haskell98
standard, but are supported by Hugs (use the -98 switch to enable
extensions) and GHC (use the -fglasgow-exts switch). I.e.:
class (Location b) => Packet a b | a -> b where
source, destination :: a -> b
size :: Num c => a -> c
...
instance Packet TestPacket TestLocation where
The class definition says that each instance of Packet uses a specific
instance of Location. The instance declaration says that, for
TestPacket, source and destination will always have type TestLocation.
--
Glynn Clements