Records in Haskell

Barney Hilken b.hilken at
Sat Feb 25 15:54:18 CET 2012

After more pondering, I finally think I understand what the DORFistas want. Here is an example:

You want to define records which describe people, and include (among other things) a field called "name". There might be several different record types with a name field, depending on whether the record refers to a customer, an employee, a business contact etc., but in each case "name" is the name of the person to which the record refers. You then write various functions which assume this, such as

>	spam :: Has r "name" String => r -> String
>	spam r = "Dear " ++ ++ "\nHave you heard..."

Now I want to define records which describe products, and I also use a field "name" in the same way, except that it is the brand name of the product. I also define functions such as

>	offer :: Has r "name" String => r -> String
>	offer r = "Reduced! " ++ ++ " 50% off!"

It doesn't make any sense to apply your functions to my records or vice-versa, but because we both chose the same label, the compiler allows it. Putting the code in separate modules makes no difference, since labels are global.

Here is a simple solution, using SORF:

The real problem is that the polymorphism of spam and offer is too general. We should each define new classes

>	class Has r "name" String => HasPersonalName r
>	class Has r "name" String => HasBrandName r

and make  each of our record types an instance of this class

>	instance HasPersonalName EmployeeRecord
>	instance HasPersonalName CustomerRecord
>	instance HasBrandName FoodRecord

then we can define functions with a more specific polymorphism

>	spam :: HasPersonalName r => r -> String
>	spam r = "Dear " ++ ++ "\nHave you heard..."

>	offer :: HasBrandName r => r -> String
>	offer r = "Reduced! " ++ ++ " 50% off!"

Now there is no danger of confusing the two uses of "name", because my records are not instances of HasPersonalName, they are instances of HasBrandName. You only use the class Has if you really want things to be polymorphic over all records, otherwise you use the more specific class.

This seems to me a much simpler approach than building the mechanism in to the language as DORF does, and it's also more general, because it isn't hard linked to the module system. Does it have any disadvantages?


More information about the Glasgow-haskell-users mailing list