Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Same variable name in Data types

Tags:

haskell

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)
like image 658
paul Avatar asked Sep 17 '25 02:09

paul


1 Answers

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.

The DuplicateRecordFields extension

The 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.

like image 122
Willem Van Onsem Avatar answered Sep 18 '25 19:09

Willem Van Onsem