Several data types with a type constructor accepting the same type, how to get the accessory of the same name?

Short: I have a solution to my problem, but it seems redundant, so I wonder if I missed something.

Long: I have 2 data types, Animal type and owner type. Both have the same “attributes” of age and name. For simplicity, I want to be able to name my age and name equally 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] 

It does not compile,

  Multiple declarations of `age' 

The same does not work with the syntax of the entry.

Thus, one person is forced to name differently the age for the owner and age for the animals.

Then I dug up a bit and found out that I could use typeclass to achieve this.

 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 using an interface in Java. The first one that doesn't work is closer to the old C-structured approach.

is there a faster way to achieve the same result?

+5
source share
1 answer

Entries (and their accessors) in Haskell ... are suboptimal. However, this particular problem regarding duplicate record fields has a workaround (starting with GHC 8.0) in the form of the DuplicateRecordFields extension. Note that write accessors should be used explicitly (there is no mosaic polymorphism).

 {-# 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] 
+6
source

Source: https://habr.com/ru/post/1273172/


All Articles