Question

A basic question about Haskell records. If I define this datatype,

data Pet = Dog { name :: String } | Cat { name :: String } deriving (Show)                           

the following works:

main = do                                                                                            
  let d = Dog { name = "Spot" }                                                                      
      c = Cat { name = "Morris" }                                                                    
  putStrLn $ name d                                                                                  
  putStrLn $ name c                                                                                  

But if I do this,

data Pet = Dog { name :: String } | Cat { name :: Integer } deriving (Show)                          

I'll get this error: Multiple declarations of 'name'.

I think I understand intuitively why this should be the case, since the type of name in the first case is just Pet -> String regardless of the constructor that was used. But I don't recall seeing this rule about record accessor functions in any of the Haskell books I've read. Can someone give a slightly more in-depth explanation about the behavior I'm seeing above?

Was it helpful?

Solution

From the Haskell '98 Report:

A data declaration may use the same field label in multiple constructors as long as the typing of the field is the same in all cases after type synonym expansion. A label cannot be shared by more than one type in scope. Field names share the top level namespace with ordinary variables and class methods and must not conflict with other top level names in scope.

I don't think there's anything more in-depth to it. As you said, the resulting field accessor has the type Pet -> String anyway so the powers that be decided it convenient to allow you to re-use the same field name in different constructors.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top