[Haskell-cafe] Qualified identifiers (Was: A better syntax for qualified operators?)

Henning Thielemann lemming at henning-thielemann.de
Wed Oct 4 07:11:28 EDT 2006


On Fri, 29 Sep 2006, Benjamin Franksen wrote:

> Brian Hulley wrote:
> > Benjamin Franksen wrote:
> >> At the danger of becoming completely off-topic now (sorry!), I have
> >> to say that I find /both/ versions ugly and unnecessarily hard to
> >> read. My personal solution is to generally avoid qualified imports.
> >
> > How does this solution scale? Surely it's only lucky if people happen to
> > choose names that don't clash with those of other modules?
>
> Many, if not most, name clashes result from two different things actually
> being "the same concept". Such entities should be refactored into classes,
> rather than disambiguated using qualified names, if possible.

That's the problem. If one instance of such a conceptual method takes one
additional parameter you cannot merge it in a class with another instance.
What about, if the functions only differ in laziness? See for instance
 http://www.cs.york.ac.uk/fp/darcs/HaXml/src/Text/XML/HaXml/Parse.hs
 http://www.cs.york.ac.uk/fp/darcs/HaXml/src/Text/XML/HaXml/ParseLazy.hs


> BTW, it has been argued by others that a single exported data type or class
> per module is a special case (however common) which cannot be generally
> assumed for library modules.

I like to use the style for the modules where it fits, and do differently
where it does not fit. However I'm trying to make the modules fit, that
is, I try to collect the functions concerning one data type in one module.

> Even in the cmmon case where there is one 'main' data type exported, you
> often need auxiliary data types (which are often concrete types) to go
> along. I would find it strange to call main concept just 'T' while the
> minor, auxiliary stuff gets a 'real' name.

Not very nice, indeed. However, I would not call them 'real' names, but
'more special' names. Say
 Text.Html.T         (main data type)
 Text.Html.Element   (auxiliary type)
 Text.Html.Attribute (auxiliary type)

 Network.URI.T          (main data type)
 Network.URI.Authority  (auxiliary type)

> As to scalability: In practice I always wait for the compiler to complain
> about ambiguous imports and only then fix like indicated above. A great
> feature of the Haskell module system is that it /never/ allows any
> ambiguity to actually appear in your source code. There is no way you could
> accidentally use an imported entity when it is not absolutely clear (to the
> compiler) which module it is imported from. OTOH, the compiler /only/
> reports an error if you actually use such an ambigously imported name.
> Otherwise the above method of 'manual' disambiguation would indeed be very
> impractical.

When reading modules, I find it difficult to find out where identifiers
come from. The foreign identifiers used in a module may not be defined in
any of the directly imported modules. This is the case if an imported
module only re-exports other module interfaces. Because of this I prefer
imports like
  import A (f,g,h)
  import qualified B
 to
  import A
  import B
 Accidentally these are the only choices in Modula languages. :-)

> > If the type is not abstract, the advantage of calling it T is just that it
> > avoids naming it twice (by type name and module name) in the situation
> > where you want to not worry about name clashes with constructors of other
> > types.
>
> You never need to worry beforehand! You can rest assured that the compiler
> will mercilessly flag all ambiguous uses of imported names. Only if and
> ehen it does you need to start thinking about how you want to name these
> different entities in your module.

A program which is written as ambigous as the compiler allows makes
reading such a program quite hard.

> ...and next come we name "the" function exported from each module 'f' or
> what? Imagine
>
>  set2 = Data.Set.Insert.f x set1

I have no preference for a particular name, but indeed, if a module merely
implements one function and there are more modules (expected) with the
same interface but different implementations, I would use the same
identifier.


More information about the Haskell-Cafe mailing list