Name clashes between field labels of different datatypes in Haskell
Coming to Haskell from a background in various OO languages, one thing that seems like a bit of a drawback to me is that function and field names aren't scoped to the types they're associated with, so it's easy to run into clashes if different datatypes have fields with the same name.
If I have these three modules:
module One where
data Foo a = Foo { value :: a }
----
module Two where
data Bar a = Bar { value :: a }
----
module Three where
import One
import Two
foo = Foo { value = 42 } -- compile error here
n = value foo -- and here
the unqualified references to value
in module Three
are considered ambiguous even though only one of the two imported names makes sense in this context. (In an OO language, references to foo.value
and bar.value
would be unambiguous.)
Of course I can disambiguate by writing Foo { One.value = 42 }
, but that looks awkward. I can also name the fields differently, e.g. "fooValue" and "barValue", but the redundancy in Foo { fooValue = 42 }
looks awkward as well.
This is really a special case of the more general issue of functions in different modules that have the same name but operate on different, unrelated types. I seem to run into it more often with field names, though. For example, I have several datatypes, not related by a type clas开发者_C百科s but often used together, that contain color values, so I'd like each one to have a field named "color".
How do experienced Haskell developers name things, and organize them into modules, to avoid this type of situation?
The GHC extension -XDisambiguateRecordFields
will allow foo = Foo { value = 42 }
(but not n = value foo
).
There's a large body of literature on the shortcomings of Haskell's current record system and candidates for its replacement, as well as a handful of libraries that attempt to provide nicer solutions now. fclabels
is the only one that I've used personally.
This StackOverflow question is similar, and some of the answers there might also be useful for you.
This is really a special case of the more general issue of functions in different modules that have the same name but operate on different, unrelated types.
Qualified imports and aliases are usually enough to solve this problem.
How do experienced Haskell developers name things, and organize them into modules, to avoid this type of situation?
I've only worked with a few experienced Haskell developers, and they do awful stuff like
data Foo a = Foo { foo_value :: a }
data Bar a = Bar { bar_value :: a }
or even
data Apocalypse a = A { ap_value :: a }
In general, I have the feeling that a lot of old-time Haskellers don't like qualified names and really want to pretend that the world has just one big name space, straight out of the dark ages. (There was a time that C compilers had the same restrictions on field names, which is why the mode in a struct stat
is called st_mode
and not just plain mode
.)
You can overload names with type classes, but the experienced developers I know don't like gratuitous type classes. I can never figure out when they think a type class will be gratuitous or not.
I hope that one day Haskell people will come to terms with a hierarchical name space and will start using qualified names. As God intended.
You might consider a type class, if there's a common accessor function on all these types. E.g.
class Fieldable a where
field :: a -> b
instance Fieldable (a,b) where
field = fst
Etc.
精彩评论