几个数据类型与Type构造函数接受相同的Type,如何获取同名的访问器?

san*_*ood 6 haskell

简短:我有一个解决我的问题的方法,但它看起来有点过分,所以我想知道我是否错过了什么.

Long:我有一个2数据类型,一个Animal类型和一个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]
Run Code Online (Sandbox Code Playgroud)

这不编译,

  Multiple declarations of `age'
Run Code Online (Sandbox Code Playgroud)

同样的事情对Record语法也不起作用.

这样做,一个人被迫为所有者命名不同的年龄和动物的年龄.

然后我挖了一下,发现我可以使用类型类来实现它.

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]
Run Code Online (Sandbox Code Playgroud)

这种方法几乎与Java中的Interface的使用相同.第一个不起作用的是更接近旧的C结构方法.

是否有更快的方法来实现相同的结果?

Ale*_*lec 6

Haskell中的记录(及其访问者)是......次优的.也就是说,关于重复记录字段的这个特殊问题有一个DuplicateRecordFields扩展形式的解决方法(自GHC 8.0起).请注意,记录访问器必须以明确的方式使用(这里没有花哨的多态性).

{-# 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] 
Run Code Online (Sandbox Code Playgroud)