Why using data types I cannot give same inner attribute name for those Data attributes?
Here I cannot reuse the variable name val
in several Data
Does not compile
data Product = Product {val::String}deriving (Show, Eq)
data Price = Price {val::Double}deriving (Show, Eq)
data Discount = Discount { val::Double }deriving (Show, Eq)
compile
data Product = Product {productVal::String}deriving (Show, Eq)
data Price = Price {priceVal::Double}deriving (Show, Eq)
data Discount = Discount { discountVal::Double }deriving (Show, Eq)
Why using data types I cannot give same inner attribute name for those Data attributes?
If you define a record type, you implicitly have constructed a "getter". If you define a record datatype like:
data Product = Product { val :: String } deriving (Show, Eq)
then Haskell will construct a function:
val :: Product -> String
that obtains the val
of a given Product
object.
If you then later define a new record datatype:
data Price = Price { val :: Double } deriving (Show, Eq)
then you thus define two versions of val
, which thus results in name clashes.
DuplicateRecordFields
extensionThe Glasgow Haskell Compiler (GHC) has, since 8.0.1, an extension DuplicateRecordFields
that allows to specify two record datatypes with the same field name.
There is no problem to use the same record name for pattern matching, or when we construct records, for example:
productToPrice :: Product -> Price
productToPrice (Product {val = x}) = Price { val = 3 }
creates no problems, since val
in Product { val = x }
clearly refers to the val
defined in the Product
data constructor, and val
in Price { val = 3 }
refers to the val
of the Price
data constructor.
If we however use val
as a function, it will create ambiguity:
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
We can add the signature of the function to specify which val
we want to use:
Prelude> (val :: Product -> String) (Product "foo")
"foo"
or by specifying the type of Product "foo"
, we obtain the same effect:
Prelude> val (Product "foo" :: Product)
"foo"
Given val
however has the same type, or has some generic meaning, it might be better to introduce a typeclass, and thus define the val
function there.
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