Short : I have a solution to my problem, but it seems overkill so I wonder if I miss something.
Long : I have a 2 data Type, an Animal type and an Owner type. Both have same "attributes" age and name. For sake of simplicity, I want to be able to call age and name indifferenly on Animal and on Owner
type Age = Int
type Name = String
data AnimalType = Dog | Cat | Snake
deriving (Read, Show,Eq)
--with datatype and pattern matching
data Animal = Animal AnimalType Name Age
deriving(Show, Eq)
name (Animal _ name _) = name
age (Animal _ _ age) = age
animalType (Animal animalType _ _) = animalType
data Owner = Owner Name Age [Animal]
deriving(Show,Eq)
name (Owner name _ _) = name
age (Owner _ age _) = age
animals (Owner _ _ animals) = animals
garfield = Animal Cat "Garfield" 8
rantanplan = Animal Dog "Rantanplan " 4
kaa = Animal Snake "Kaa" 15
dupond = Owner "Dupont" 28 [garfield, rantanplan]
bob = Owner "Bob" 35 [kaa]
This does not compile,
Multiple declarations of `age'
The same thing does not work neither with Record syntax.
Doing so, one is forced to name differently age for Owner and age for Animal.
Then I dug a bit and found out that I could use typeclass to achieve that.
type Age = Int
type Name = String
class Nameable a where
name:: a -> Name
class Ageable a where
age:: a -> Age
data AnimalType = Dog | Cat | Snake
deriving (Read, Show,Eq)
--with datatype and pattern matching
data Animal = Animal AnimalType Name Age
deriving(Show, Eq)
instance Nameable Animal where
name (Animal _ name _) = name
instance Ageable Animal where
age (Animal _ _ age) = age
animalType (Animal animalType _ _) = animalType
data Owner = Owner Name Age [Animal]
deriving(Show,Eq)
instance Nameable Owner where
name (Owner name _ _) = name
instance Ageable Owner where
age (Owner _ age _) = age
animals (Owner _ _ animals) = animals
garfield = Animal Cat "Garfield" 8
rantanplan = Animal Dog "Rantanplan " 4
kaa = Animal Snake "Kaa" 15
dupond = Owner "Dupont" 28 [garfield, rantanplan]
bob = Owner "Bob" 35 [kaa]
This approach is almost identical to usage of Interface in Java. The first one that does not work is closer to old C struct approach.
is there a quicker way to achieve the same result ?
Records (and their accessors) in Haskell are... suboptimal. That said, this particular issue regarding duplicate record fields has a workaround (since GHC 8.0) in the form of the DuplicateRecordFields
extension. Note that the record accessors have to be used in an unambiguous fashion (there is no fancy polymorphism happening here).
{-# LANGUAGE DuplicateRecordFields #-}
type Age = Int
type Name = String
data AnimalType = Dog | Cat | Snake
deriving (Read, Show, Eq)
data Animal = Animal
{ animalType :: AnimalType
, name :: Name
, age :: Age
} deriving(Show, Eq)
data Owner = Owner
{ name :: Name
, age :: Age
, animals :: [Animal]
} deriving(Show, Eq)
garfield = Animal Cat "Garfield" 8
rantanplan = Animal Dog "Rantanplan " 4
kaa = Animal Snake "Kaa" 15
dupond = Owner "Dupont" 28 [garfield, rantanplan]
bob = Owner "Bob" 35 [kaa]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With