Avoiding namespace pollution in Haskell

I'm using lots of different records in a program, with some of them using the same field names, e.g.

data Customer = Customer { ..., foo :: Int, ... }
data Product = Product { ..., foo :: Int, ... }

Now as the accessor function "foo" is defined twice, I get the "Multiple declarations" error. One way to avoid this would be using different modules that are imported fully qualified, or simply renaming the fields (which I don't want to do).

What is the officially suggested way of dealing with this 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.

Haskell: Using qualified imports to avoid polluting the namespace , In most of the Haskell code I've read any functions from other modules have been imported directly into the namespace and I reached the stage  30 Dec 2012 · haskell Haskell: Using qualified imports to avoid polluting the namespace In most of the Haskell code I've read any functions from other modules have been imported directly into the namespace and I reached the stage where I had this list of imports in a file:

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

Rant: I love Haskell, but hate its "import" syntax/conventions : haskell, Bar import baz , which, in addition to preventing namespace pollution, gives me a quick way to know where the function came from. (edit 5pm PDT: This also  Avoiding namespace pollution. Javascript don't support function overloading.So when any two functions with same name are used, one function will override the other function depending on the order these functions are loading.

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.

The Glasgow Haskell Compiler User's Guide, Version 3.02: GHC , To avoid having to be in the monad to call a C function, it is possible to use unsafePerformIO , which is available from the IOExts module. There are three  use records in Haskell, which share field names. use lenses for accessing these fields use bindings in code with the same name as the record's fields avoiding any namespace clashes avoid overly verbose code and boilerplate as much as possible.

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

Known bugs and infelicities, Namespace pollution. Several modules internal to GHC are visible in the standard namespace. All of these modules begin with Prel, so the rule is: don't use any  It's good engineering practice to tidy up your APIs as you learn more about effective ways to use them in practice, and to avoid namespace pollution. It's good engineering practice to not break old code. and 2. have always been and always will be in tension thus a balance point must be found.

One possible solution that will make your code less verbose is to define <.> as:

(<.>) :: (Emiter e1, Emiter e2) => e1 -> e2 -> String
lhs <.> rhs = emit lhs <> emit rhs

Then emitters can look like:

class Emiter n where
    emit :: n -> String 

instance Emiter String where
    emit = id

instance Emiter A where 
    emit A {
        foo = foo'
        bar = bar'
    } = foo' <.> "--" <.> bar'

instance Emiter B where
    emit B {
        foo = foo'
        bar = bar'
    } =  "[" <.> bar' <.> foo' <.> "]"

name spacing · Wiki · Glasgow Haskell Compiler / GHC · GitLab, Note that a data declaration now creates a module-like namespace, what they do now: structuring their programs to avoid name collisions. There are several partial functions in the Haskell standard library. If you use them, you always risk to end up with an undefined. If you use them, you always risk to end up with an undefined. In this article we give some hints how to avoid them, leading to code that you can be more confident about.

LIO, Hence main modules consisting mostly of IO code that simply need to run LIO code should import LIO.Run (or LIO.DCLabel) to avoid polluting their namespaces. Haskell modules are a useful way to group a set of related functionalities into a single package and manage different functions that may have the same names. The module definition is the first thing that goes in your Haskell file. A basic module definition looks like:

Dynamic Language Embedding With Homogeneous Tool Support, Haskell OOO. up such an internal language are usually visible on a specific object or in a specific scope only, to avoid the pollution of the global namespace. Note that I prefer to import modules as qualified, to avoid namespace: pollution and confusion. I would rather see "Char.isLetter" in code: rather than "isLetter". > import qualified System > import qualified Data.List as List > import qualified Data.Char as Char > import qualified Data.HashMap.Strict as HashMap

LANGUAGE Safe #-} {-, DCLabel") to avoid polluting their namespaces. Most code will need to use a particular label format, which needs to be imported separately. Hence, a typical set  This is where you avoid namespace pollution. \$\endgroup\$ – V. Semeria Sep 12 '16 at 14:58 \$\begingroup\$ Why do a and b need extra lets and the second line in first let does not? \$\endgroup\$ – BitTickler Sep 12 '16 at 15:00

Comments
  • I share your pain. I come from the OO world.
  • So it looks like I'll go with the qualified imports -- at least for this project. Thank you all for your answers! This is one of those moments when I miss Scheme macros for getting rid of the DRY violations when using typeclasses...
  • I have found this project page about OverloadedRecordFields extension for GHC to allow multiple record datatypes to share the same field names.
  • Good point about the recursive dependencies. But as stated in the linked thread, "I found the lack of this feature to be forcing me to design modules in a tree like structure. And this actually helped me to avoid some bad design. Sometimes [...] I declared mutual dependencies by error - error messages helped be to debug this." So for now I'll stick with fully qualified imports and split my record definitions into multiple files. Maybe go the typeclass approach later, but for now it looks like overkill...
  • The more common tag syntax, which I use, is c_foo.
  • The typeclass approach looks promising, but adds a lot of code duplication, as there are many common fields in my data definition (e.g. productId, customerId etc.) that I would need to handle in each typeclass instance again. Instead of renaming I'll rather use the qualified imports to have "real" namespaces.
  • The type class approach is really unrealistic. It would require creating a separate type class for every named field for which one would like to have common property patterns (getters, setters, modifiers). This is exactly what the record syntax is meant to avoid.
  • This answer is 4 years old. Certainly one can use Lenses to address most needs these days.
  • Wow! Just realized how much there really is still to learn for me when it comes to Haskell. For my current project this looks like overkill, but I'll have a closer look at your links.