数据类型中的变量名称相同

时间:2018-11-25 10:31:12

标签: haskell

为什么使用数据类型时不能为这些数据属性提供相同的内部属性名称?

在这里,我无法在多个数据中重用变量名val

不编译

data Product = Product {val::String}deriving (Show, Eq)
data Price = Price {val::Double}deriving (Show, Eq)
data Discount = Discount { val::Double }deriving (Show, Eq)

编译

data Product = Product {productVal::String}deriving (Show, Eq)
data Price = Price {priceVal::Double}deriving (Show, Eq)
data Discount = Discount { discountVal::Double }deriving (Show, Eq)

1 个答案:

答案 0 :(得分:4)

  

为什么使用数据类型时不能为这些数据属性提供相同的内部属性名称?

如果定义记录类型,则隐式构造了一个“ getter”。如果您定义记录数据类型,例如:

data Product = Product { val :: String } deriving (Show, Eq)

然后Haskell将构造一个函数:

val :: Product -> String

获得给定val对象的Product

如果以后再定义新的记录数据类型:

data Price = Price { val :: Double } deriving (Show, Eq)

然后,您定义val的两个版本,从而导致名称冲突。

DuplicateRecordFields扩展名

格拉斯哥Haskell编译器(GHC)自8.0.1起具有扩展名DuplicateRecordFields,该扩展名允许指定两个具有相同字段名称的记录数据类型。

使用相同的记录名称进行模式匹配或构造记录时没有问题,例如:

productToPrice :: Product -> Price
productToPrice (Product {val = x}) = Price { val = 3 }

不会造成任何问题,因为val中的Product { val = x }显然引用了val数据构造函数中定义的Product和{{1}中的val }指的是Price { val = 3 }数据构造函数的val

但是,如果我们使用Price作为函数,则会产生歧义:

val

我们可以添加函数的签名以指定要使用的Prelude> val (Product "foo") <interactive>:15:1: error: Ambiguous occurrence ‘val’ It could refer to either the field ‘val’, defined at <interactive>:1:25 or the field ‘val’, defined at <interactive>:2:21

val

或通过指定Prelude> (val :: Product -> String) (Product "foo") "foo" 的类型,我们获得相同的效果:

Product "foo"

鉴于Prelude> val (Product "foo" :: Product) "foo" 具有相同的类型或具有某种通用含义,最好引入类型类,然后在其中定义val函数。