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.
(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.
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
See also the Has package: http://chrisdone.com/posts/duck-typing-in-haskell
And if you really need extensible records now, you can always use HList. But I wouldn't recommend this until you're really familiar and comfortable with medium-advanced Haskell, and even then I'd triple check you need it.
Haskelldb has a slightly more lightweight version: http://hackage.haskell.org/packages/archive/haskelldb/2.1.0/doc/html/Database-HaskellDB-HDBRec.html
And then there's another version of extensible records as part of the grapefruit frp library: http://hackage.haskell.org/package/grapefruit-records
Again, for your purposes, I'd bite the bullet and just rename the fields. But these references are to show that when you really need the full power of extensible records, there are ways to do it, even if none are as pleasant as a well-designed language extension would be.
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