开发者

Name clashes between field labels of different datatypes in Haskell

开发者 https://www.devze.com 2023-01-08 08:00 出处:网络
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,

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消