Avoiding namespace pollution in Haskell
This is a very hairy problem. There are several proposals for fixing the record system. On a related note, see TDNR and related discussion on cafe.
Using the currently available language features, I think the best option is defining the two types in two different modules, and doing a qualified import. On top of this, if you want, you can implement some type class machinery.
In Customer.hs
module Customer where
data Customer = Customer { ..., foo :: Int, ... }
In Product.hs
module Product where
data Product = Product { ..., foo :: Int, ... }
While using them, in Third.hs
module Third where
import qualified Customer as C
import qualified Product as P
.. C.foo ..
.. P.foo ..
Yet, I imagine it won't be too late before you hit the problem about recursively dependent modules.
There's a language extension DuplicateRecordFields
that allows duplication of field functions and makes its type to be inferred by type annotation.
Here is a little example (haskell-stack script):
#!/usr/bin/env stack
-- stack runghc --resolver lts-8.20 --install-ghc
{-# LANGUAGE DuplicateRecordFields #-}
newtype Foo = Foo { baz :: String }
newtype Bar = Bar { baz :: String }
foo = Foo { baz = "foo text" }
bar = Bar { baz = "bar text" }
main = do
putStrLn $ "Foo: " ++ baz (foo :: Foo) -- Foo: foo text
putStrLn $ "Bar: " ++ baz (bar :: Bar) -- Bar: bar text
(FYI, this question is almost certainly a duplicate)
Solutions:
1) Prefix the fields with a tag indicating the type (extremely common)
data Customer = Customer {..., cFoo :: Int, ...}
2) Use type classes (less common, people complain prefixes like cFoo
are inconvenient but evidently not so bad that they will write a class and instance or use TH to do the same).
class getFoo a where
foo :: a -> Int
instance getFoo Customer where
foo = cFoo
3) Use better field names If the fields are actually different (which isn't always true, my computer has an age as does my employee), then this is the best solution.