
Hi! The last two weeks I've seen two new packages that add suffixes to identifiers instead of relying on them being imported qualified to distinguish them from identifiers in other modules. This is not a new thing in Haskell community and there are examples of this practice in libraries shipped with GHC. It is also common in papers (for good reasons as we will see later). Atomic channels and variables under Control.Concurrent.* are examples of using a prefix as a namespacing tool. Let me reiterate the arguments [1,2] against this practice and also speculate why this practice is more common in Haskell than in e.g. Python, Java or Ruby. * Cons of including a namespace prefix/suffix in identifiers 1. From experience these prefixes/suffixes tend to be short and non-descriptive, typically just one letter e.g. foldU or elemB. Very frequently used functions that every Haskell programmer is likely to use often can have shorter name as the cost of memorizing them is amortized over all their uses. Examples of short names that most Haskell programmers know by heart is map, fold*, etc. Given that your library won't see the same use as these functions your functions need more descriptive names (or in this case use a qualified import that makes them more descriptive e.g. Array.fold). 2. If your modules are imported qualified the suffix is redundant and thus wastes space. Consider for example foldU imported qualified from the module Data.Array as Array.foldU. Array.fold would have been better in this case. * Pros of using qualified imports 1. Your code will be more robust against additions to modules you depend on. Consider this snippet: import Some.Module -- An utility function that the author of the above module forgot to include. foo = ... Now the author of Some.Module releases a new version of his or her package which include `foo' and your code no longer compiles. If you have no imports on the form import Some.Module your package can specify more relaxed version dependencies on other packages [3]. 2. It's easier to see from where an identifier is imported. Just check the functions module prefix (e.g. Array in Array.foo). If you renamed the import using import Foo as F you might have to check the import list. * Explicit, unqualified imports An alternative to qualified imports that shares some of benefits is to import names unqualified but explicitly enumerate the function names e.g. import Some.Module (foo, bar) It is still not immediately obvious what module a name refers too when using this style (point 2 under pros above) but it is at least easier to find than when implicitly importing all names from a module. This is my current preference for infix operators as they look quite ugly qualified with a module name. It might also make sense if a few functions (e.g. parser combinators) are used a lot in the same module (e.g. an HTTP parser). * Why is this practice common in Haskell Here are some guesses: 1. It's common in papers. However, papers and libraries are quite different. The former usually build up a small vocabulary and having short names is a big win. Papers rarely make use of the module system at all. The latter are included as pieces of large programs and their names need to be adjusted accordingly. 2. It's the default. You have to add "qualified" to all your imports to make them qualified. In most language imports are qualified by default. I think the latter would have been a better choice but we have to live with the current design so bite the bullet and add those qualified keywords to your imports. 3. Lack of common interfaces. An example would be two different set implementations that essentially have the same interface but since there is no explicitly shared interface, defined using a type class, you sometimes end up with different names. The lack of type families might explain why e.g. collection classes don't share interfaces. 4. Haskell is a very expressive language. You can often write a whole function definition on one line! Adding those module qualifications makes your code slightly longer and it might just break your beautiful one liner into two lines. * Summary Whenever you write a library design it so it works well with qualified imports. That means leaving namespacing issues to the module system. Try to think of how code using your functions will look like if it uses them qualified. * References 1. http://www.haskell.org/haskellwiki/Import_modules_properly 2. http://www.haskell.org/haskellwiki/Qualified_names 3. See section 2 Version numbers - http://www.haskell.org/haskellwiki/Library_versioning_policy Cheers, Johan

On Thu, 5 Jun 2008, Johan Tibell wrote:
Hi!
The last two weeks I've seen two new packages that add suffixes to identifiers instead of relying on them being imported qualified to distinguish them from identifiers in other modules. This is not a new thing in Haskell community and there are examples of this practice in libraries shipped with GHC. It is also common in papers (for good reasons as we will see later). Atomic channels and variables under Control.Concurrent.* are examples of using a prefix as a namespacing tool. Let me reiterate the arguments [1,2] against this practice and also speculate why this practice is more common in Haskell than in e.g. Python, Java or Ruby.
Thank you for emphasising these points, again!

Am Donnerstag, 5. Juni 2008 17:19 schrieb Johan Tibell:
[…]
2. It's the default. You have to add "qualified" to all your imports to make them qualified. In most language imports are qualified by default. I think the latter would have been a better choice but we have to live with the current design so bite the bullet and add those qualified keywords to your imports.
If you leave out “qualified”, you still get the qualified names imported. And if you use conflicting identifiers always qualified then there’s no problem. For example, you can use import Data.Set as Set import Data.List as List and then just say Set.null or List.null.
[…]
* Summary
Whenever you write a library design it so it works well with qualified imports. That means leaving namespacing issues to the module system. Try to think of how code using your functions will look like if it uses them qualified.
I totally agree.
[…]
Best wishes, Wolfgang

On Jun 6, 2008, at 8:12 AM, Wolfgang Jeltsch wrote:
Am Donnerstag, 5. Juni 2008 17:19 schrieb Johan Tibell:
[…]
2. It's the default. You have to add "qualified" to all your imports to make them qualified. In most language imports are qualified by default. I think the latter would have been a better choice but we have to live with the current design so bite the bullet and add those qualified keywords to your imports.
If you leave out “qualified”, you still get the qualified names imported. And if you use conflicting identifiers always qualified then there’s no problem. For example, you can use
import Data.Set as Set import Data.List as List
and then just say Set.null or List.null.
There's one caveat: Always choose descriptive names, even if you are assuming that you will usually use a qualified import. The following are wonderful names, even though they conflict with the prelude: null filter map lookup The following are terrible names: T C What's a T? What's a C? There's no excuse to give something a lousy name just because the enclosing module is descriptively named. I reject the naming conventions used by ML modules when writing Haskell code: Haskell modules are not ML modules. -Jan-Willem Maessen

Jan-Willem Maessen
On Jun 6, 2008, at 8:12 AM, Wolfgang Jeltsch wrote:
Am Donnerstag, 5. Juni 2008 17:19 schrieb Johan Tibell:
[…]
2. It's the default. You have to add "qualified" to all your imports to make them qualified. In most language imports are qualified by default. I think the latter would have been a better choice but we have to live with the current design so bite the bullet and add those qualified keywords to your imports.
If you leave out “qualified”, you still get the qualified names imported. And if you use conflicting identifiers always qualified then there’s no problem. For example, you can use
import Data.Set as Set import Data.List as List
and then just say Set.null or List.null.
There's one caveat: Always choose descriptive names, even if you are assuming that you will usually use a qualified import. The following are wonderful names, even though they conflict with the prelude: null filter map lookup
import Prelude as P
The following are terrible names: T C
Not to mention that this usage is hideously confusing while looking at the haddock docs. While I don't mind Haskore having them, they should just be different names for a type that has a clear name. It also appears to generate an excessive amount of modules. -- (c) this sig last receiving data processing entity. Inspect headers for past copyright information. All rights reserved. Unauthorised copying, hiring, renting, public performance and/or broadcasting of this signature prohibited.

On Fri, 6 Jun 2008, Achim Schneider wrote:
Jan-Willem Maessen
wrote: There's one caveat: Always choose descriptive names, even if you are assuming that you will usually use a qualified import. The following are wonderful names, even though they conflict with the prelude: null filter map lookup
import Prelude as P
The following are terrible names: T C
Not to mention that this usage is hideously confusing while looking at the haddock docs.
But that will be resolved when Haddock can show identifiers with qualifications.
While I don't mind Haskore having them, they should just be different names for a type that has a clear name. It also appears to generate an excessive amount of modules.
It's good to have fine grained modules, because you can more easily exchange the parts you want different from the standard way. For reducing import lists for simple songs I think we could provide wrapper modules.

On Jun 6, 2008, at 12:54 PM, Henning Thielemann wrote:
On Fri, 6 Jun 2008, Achim Schneider wrote:
Jan-Willem Maessen
wrote: There's one caveat: Always choose descriptive names, even if you are assuming that you will usually use a qualified import. The following are wonderful names, even though they conflict with the prelude: null filter map lookup
import Prelude as P
Precisely. If I import the prelude qualified and your library unqualified, is my code readable? I should hope it is. And if the library used the overlapping names reasonably, you shouldn't be left wondering when you read my code.
The following are terrible names: T C
Not to mention that this usage is hideously confusing while looking at the haddock docs.
But that will be resolved when Haddock can show identifiers with qualifications.
I specifically *didn't* bring up the Haddock issue, because I think it's a side show. Fundamentally, these types are neither clear nor descriptive. Their treatment by one or another documentation tool is, at some level, beside the point.
It's good to have fine grained modules, because you can more easily exchange the parts you want different from the standard way. For reducing import lists for simple songs I think we could provide wrapper modules.
Make your modules as small as you like; small modules are great. But keep things readable, please! -Jan
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

G'day all.
Quoting Jan-Willem Maessen
There's one caveat: Always choose descriptive names, even if you are assuming that you will usually use a qualified import. The following are wonderful names, even though they conflict with the prelude: null filter map lookup
On the contrary, these are terrible names _because_ they conflict with the Prelude. Especially "map", for which there's no excuse. If it does the obvious thing, it's far better to define a real Functor instance. It's okay if you highly encourage or effectively mandate qualified import, like Data.Map does. However, unlike Data.Map, if you do that then please don't define any operators. Requiring someone to type m M.! k is just wrong. Cheers, Andrew Bromage

ajb@spamcop.net writes:
null filter map lookup
On the contrary, these are terrible names _because_ they conflict with the Prelude.
I agree. One solution would be to stuff these into Data.List.
It's okay if you highly encourage or effectively mandate qualified import, like Data.Map does.
I think designing modules for qualified-only use is a mistake. I also think import lists get quite ugly, with multiple instances of import qualified Data.Set as S import Data.Set (Set) for multiple - sometimes even the majority - of modules. Add to this that people will assign a variation of abbreviations for modules, we quickly lose consistency. And - is there a way to make GHCi use aliased qualification? I find my self typing detailed taxonomies all the time there. For Haskell', I would relly like to have good, generic classes/interfaces for this, so that a) code becomes readable (including import lists), and b) code can be written more generically, and c) it becomes easier to switch between e.g. different string types. -k -- If I haven't seen further, it is by standing in the footprints of giants

On Mon, 2008-06-09 at 16:04 +0200, Ketil Malde wrote:
I think designing modules for qualified-only use is a mistake. I also think import lists get quite ugly, with multiple instances of
import qualified Data.Set as S import Data.Set (Set)
for multiple - sometimes even the majority - of modules.
As far as I can see that is the only downside, having to import more than once to get the type name unqualified with the rest of the module qualified.
Add to this that people will assign a variation of abbreviations for modules, we quickly lose consistency.
The obvious consistent thing to do is to use the last part of the module name, at least for short names like Set and Map. For ByteString it is more of a mouthful. import qualified Data.Set as Set import Data.Set (Set) Set.empty, Set.insert etc etc.
And - is there a way to make GHCi use aliased qualification? I find my self typing detailed taxonomies all the time there.
The ghci syntax currently is: :m Data.Set wouldn't it be much nicer as: import Data.Set then we could have the obvious: import Data.Set as Set Duncan

* On Monday, June 09 2008, Duncan Coutts wrote:
And - is there a way to make GHCi use aliased qualification? I find my self typing detailed taxonomies all the time there.
The ghci syntax currently is: :m Data.Set wouldn't it be much nicer as: import Data.Set then we could have the obvious: import Data.Set as Set
ghci does load modules when you type "import Data.Set" already, but it doesn't parse "import Data.Set as Set"

On Mon, 9 Jun 2008, Duncan Coutts wrote:
On Mon, 2008-06-09 at 16:04 +0200, Ketil Malde wrote:
And - is there a way to make GHCi use aliased qualification? I find my self typing detailed taxonomies all the time there.
The ghci syntax currently is: :m Data.Set wouldn't it be much nicer as: import Data.Set then we could have the obvious: import Data.Set as Set
This would be nice! Feature request?

Henning Thielemann wrote:
On Mon, 9 Jun 2008, Duncan Coutts wrote:
On Mon, 2008-06-09 at 16:04 +0200, Ketil Malde wrote:
And - is there a way to make GHCi use aliased qualification? I find my self typing detailed taxonomies all the time there.
The ghci syntax currently is: :m Data.Set wouldn't it be much nicer as: import Data.Set then we could have the obvious: import Data.Set as Set
This would be nice! Feature request?
feature request filed for this, http://hackage.haskell.org/trac/ghc/ticket/2362 . For extending the import syntax in general, I wasn't sure we knew quite what we wanted yet, so it seemed a little premature for a feature request. (the first step in "implementing" the feature request would have to be specifying an exact design and probably asking for community feedback). So let's talk about what we do or don't want for that one some more, perhaps.

On Mon, Jun 9, 2008 at 4:04 PM, Ketil Malde
I think designing modules for qualified-only use is a mistake. I also think import lists get quite ugly, with multiple instances of
I was only suggesting avoiding namespacing prefixes/suffixes in identifiers. Other than that things would be the same. You don't have to import things as qualified. However, if you're going to try to avoid using identifiers in your exported interface because they would collide with other modules I would advice against it. I agree with you that the module imports get a bit ugly. I prefer that to the alternative though.
Add to this that people will assign a variation of abbreviations for modules, we quickly lose consistency.
It's a shame that we have such deep hierarchies otherwise we wouldn't need to always alias out module imports. I think Python get's it right: import os ... os.tmpname ... Duncan's recommendation of just taking the part after the last dot seems like a good rule of thumb. Doing import qualified Data.Map as M does gain you much in my opinion. Compare M.empty to emptyM. No difference, you still can't deduce the module by just looking at the call site. Cheers, Johan

"Johan Tibell"
Duncan's recommendation of just taking the part after the last dot seems like a good rule of thumb. Doing
import qualified Data.Map as M
does gain you much in my opinion. Compare M.empty to emptyM. No difference, you still can't deduce the module by just looking at the call site.
I would prefer `M.empty' to `emptyM'. At least, by looking at `M.empty', you know that this `empty' is from `M' and you can easily check out what `M' is from the import list. I personally always found myself unproductively tracing back something like `emptyM' to its origin.
Cheers,
Johan
-- c/* __o/* <\ * (__ */\ <

Excerpts from johan.tibell's message of Mon Jun 09 21:53:50 +0200 2008:
On Mon, Jun 9, 2008 at 4:04 PM, Ketil Malde
wrote: I think designing modules for qualified-only use is a mistake. I also think import lists get quite ugly, with multiple instances of
I was only suggesting avoiding namespacing prefixes/suffixes in identifiers. Other than that things would be the same. You don't have to import things as qualified. However, if you're going to try to avoid using identifiers in your exported interface because they would collide with other modules I would advice against it. I agree with you that the module imports get a bit ugly. I prefer that to the alternative though.
Add to this that people will assign a variation of abbreviations for modules, we quickly lose consistency.
It's a shame that we have such deep hierarchies otherwise we wouldn't need to always alias out module imports. I think Python get's it right:
import os
... os.tmpname ...
Duncan's recommendation of just taking the part after the last dot seems like a good rule of thumb. Doing
import qualified Data.Map as M
does gain you much in my opinion. Compare M.empty to emptyM. No difference, you still can't deduce the module by just looking at the call site.
Coming from a world where qualified names at call sites or full import (open) are the default rules (OCaml), I much prefer the import way (where you specify names that gets imported) and thus prefer when names don't collide (except for modules like Data.Map or ByteString where I use the "as" notation). The key point for me is to be able to trace as fast as possible what precisely use a module by looking (only) at the top of the file. Best regards, -- Nicolas Pouillard aka Ertai

Ketil Malde wrote:
And - is there a way to make GHCi use aliased qualification? I find my self typing detailed taxonomies all the time there.
For Haskell', I would relly like to have good, generic classes/interfaces for this, so that a) code becomes readable (including import lists), and b) code can be written more generically, and c) it becomes easier to switch between e.g. different string types.
Class abstraction is not zero cost. Abstract far enough that GHC can't see how to resolve dictionaries at compile time (insufficient inlining) and you will not only slow things down just because of the dictionary cost, you'll also break all those nice RULES and lose your fusion. As for import syntax / readability, whilst I'm familiar with the problems (most are mentioned in this thread) I'm not aware of any concrete proposal to improve the situation. Jules

Johan Tibell wrote:
* Why is this practice common in Haskell
Here are some guesses:
1. It's common in papers.
Maybe.
2. It's the default.
Probably not.
3. Lack of common interfaces.
Yes. It's really quite frustrating that it is 100% impossible to write a single function that will process lists, arrays, sets, maps, byte strings, etc. You have to write several different versions. OK, so some functions really don't make sense for a set because it's unordered, and some functions don't make sense for a map, and so forth. But for example, if I write some complicated algorithm that uses a list to store data and I change that to a set instead, I now have to wade through the function changing every operation from a list-op into a set-op. It's really very annoying! The problem - as I'm sure everybody is well aware - is that it's rather hard to come up with a type system formulation that works even though lists and arrays can store everything, unboxed arrays can only store types X, Y and Z, sets and maps require ordered data, byte strings only store bytes, and so on and so forth.
4. Haskell is a very expressive language. You can often write a whole function definition on one line! Adding those module qualifications makes your code slightly longer and it might just break your beautiful one liner into two lines.
5. Writing "Hello" Prelude.++ "World" is just ugly. ;-) In addition, I feel I should point out that only *very* recently did I discover that it is in fact possible to import a module qualified and still be able to refer to it easily. What do I mean by that? Well, suppose I do import Text.ParserCombinators.Parsec I do *not* want to have to write "Text.ParserCombinators.Parsec.runParser"!! Until very recently, it was not at all clear to me that there is actually a very simple solution to this problem: import Text.ParserCombinators.Parsec as P Now I only have to write "P.runPaser", which is much shorter. This fact probably needs to be mentioned more loudly - I'm sure I'm not the only person to have overlooked it...

On Fri, Jun 6, 2008 at 8:35 PM, Andrew Coppin
import Text.ParserCombinators.Parsec as P
Now I only have to write "P.runPaser", which is much shorter.
Or maybe even
import Text.ParserCombinators.Parsec as Parser
and then `Parser.run'. Having the module hierarchy be shallower so you don't have to add a `as' to every import might also help. I think Python does this better for common modules which have short and sweet name lite `system'. Cheers, Johan

On Friday 06 June 2008, Andrew Coppin wrote:
It's really quite frustrating that it is 100% impossible to write a single function that will process lists, arrays, sets, maps, byte strings, etc. You have to write several different versions. OK, so some functions really don't make sense for a set because it's unordered, and some functions don't make sense for a map, and so forth. But for example, if I write some complicated algorithm that uses a list to store data and I change that to a set instead, I now have to wade through the function changing every operation from a list-op into a set-op. It's really very annoying!
It's not 100% impossible, depending on what exactly you're doing. For instance... Set a, ByteStrings, Seq a, Map k a and [a] are Monoids Set, Array i, Map k, Tree, Seq and [] are Foldable functors Array i, Map k, Tree, Seq, Tree and [] are Traversable functors Those can get you lots of operations (folds, maps, unions...) although there may be gaps that could be filled (Foldable is sufficient to define null, for instance, but it isn't in Data.Foldable). There's also the collections library (or Edison, if that's more your style) on hackage that takes such things a lot further. It seems it needs to be tweaked a bit to run on 6.8 according to the log, though. And there's also the issue of whether you can make all such generic operations perform well enough for every instance without making gigantic type classes that allow you to override every single operation (or if you can't, which way do you sacrifice). Of course, the prelude isn't a very good example of this sort of thing, so if that's the only place one looks (or in any module specific to one particular data structure), there's not much to find. -- Dan

On Sat, Jun 7, 2008 at 3:03 PM, Dan Doel
On Friday 06 June 2008, Andrew Coppin wrote:
It's really quite frustrating that it is 100% impossible to write a single function that will process lists, arrays, sets, maps, byte strings, etc. You have to write several different versions. OK, so some functions really don't make sense for a set because it's unordered, and some functions don't make sense for a map, and so forth. But for example, if I write some complicated algorithm that uses a list to store data and I change that to a set instead, I now have to wade through the function changing every operation from a list-op into a set-op. It's really very annoying!
It's not 100% impossible, depending on what exactly you're doing. For instance...
Set a, ByteStrings, Seq a, Map k a and [a] are Monoids Set, Array i, Map k, Tree, Seq and [] are Foldable functors Array i, Map k, Tree, Seq, Tree and [] are Traversable functors
Those can get you lots of operations (folds, maps, unions...) although there may be gaps that could be filled (Foldable is sufficient to define null, for instance, but it isn't in Data.Foldable).
These do help in the case you want to traverse data structures that share a set of properties (e.g. are Functors). However, it doesn't address the problem of sharing an interface among Set, IntSet, ByteSet, etc. In other words there's a need for a Set type class. Hopefully type families will help us write such an interface and keep it efficient. Cheers, Johan

Andrew Coppin wrote:
Until very recently, it was not at all clear to me that there is actually a very simple solution to this problem:
import Text.ParserCombinators.Parsec as P
Now I only have to write "P.runPaser", which is much shorter.
This fact probably needs to be mentioned more loudly - I'm sure I'm not the only person to have overlooked it...
I have one efficient way to find all the needed language features without reading the specification from the start to the end or waiting till my questions get answered. The point is that common sense will indicate you where the required features should be logically located in the language grammar. E.g. if you want something related to imported modules it is logical to check all the alternatives available in import declaration. Then I check the grammar how the production for import declaration (impdelc) looks like (where it can be used etc.). Mostly it is enough sometimes I need to check the language specification since it is not obvious from the grammar. The result is that when I learn a new language the first thing I'm looking for is the formal grammar. Luckily most languages have it available. Some languages (like Haskell) are obsessed with shortcuts and the result is that their grammar is a bit cryptic; others (like VHDL) have it just great - production names clearly indicate what they actually do. On the other side haskell has nice online report :-) Peter.

On Fri, Jun 6, 2008 at 2:35 PM, Andrew Coppin
Johan Tibell wrote:
3. Lack of common interfaces.
Yes.
It's really quite frustrating that it is 100% impossible to write a single function that will process lists, arrays, sets, maps, byte strings, etc. You have to write several different versions. OK, so some functions really don't make sense for a set because it's unordered, and some functions don't make sense for a map, and so forth. But for example, if I write some complicated algorithm that uses a list to store data and I change that to a set instead, I now have to wade through the function changing every operation from a list-op into a set-op. It's really very annoying!
I can think of at least two ways I have been able to keep generic code generic, in the way you describe: 1. Use the Data.Foldable interface. Lists, Sets, Sequences and Trees are all foldable. This doesn't help with your complaint about arrays and bytestrings, but it's something. You can do a lot with Foldable. 2. Factor out the operations *your app uses* into a typeclass. For some code I was writing I wrote the following interface -- | Represents a container of type @t@ storing elements of type @a@ that -- support membership, insertion, and deletion. class Ord a => Setlike t a where -- | The set-like object with an element removed. without :: t -> a -> t -- | The set-like object with an element included. with :: t -> a -> t -- | Whether the set-like object contains a certain element. contains :: t -> a -> Bool [Aside: This could be made H98 easily, but I didn't need it to be.] By implementing this class for various types (sets and lists, as well as a few others I used) I achieved the implementation-agnosticism you described at fairly low cost. If I needed to change out a list for an array, I only changed the code that creates the initial data structure, or the signature in the actual record containing the type --- in other words, I only changed what needed to be changed, and the rest was inferred. The reason I think it makes sense for *me* to have created and implemented this interface, instead of a library writer, is that for each task that is data-structure agnostic in some respect, you will need a *different* set of operations. I know which ones I need, so I should make only those generic. The library writer, to be generic, would have to write interfaces for all combinations of operations one might care about (too many for this not to be a waste of time) and that *still* wouldn't be good enough, because certain operations have slightly differing semantics (or signatures) that make genericity inadvisable (e.g. Set.map does not preserve the length of the input list, but List.map does. If your code relies on this rule about "map", it is bad to use an interface with a "generic" map). Perhaps there are certain, small, common interfaces --- like Setlike --- that could be agreed upon. But some people will always clamor that it doesn't fit their application, or doesn't have the right methods. Which I think is okay, if we don't ask too much of standard libs. -- Denis

2008/6/6 Andrew Coppin
Until very recently, it was not at all clear to me that there is actually a very simple solution to this problem:
import Text.ParserCombinators.Parsec as P
Now I only have to write "P.runPaser", which is much shorter.
Err, I have a beginner question, then: Is there any difference between: import Very.Long.Module.Name as M and: import qualified Very.Long.Module.Name as M ? Loup

Hello Loup, Saturday, June 7, 2008, 7:31:29 PM, you wrote:
Is there any difference between:
import Very.Long.Module.Name as M
and:
import qualified Very.Long.Module.Name as M
with first you get *both* qualified and unqualified identifiers, with second - only qualified -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Am Samstag, 7. Juni 2008 17:31 schrieb Loup Vaillant:
2008/6/6 Andrew Coppin
: Until very recently, it was not at all clear to me that there is actually a very simple solution to this problem:
import Text.ParserCombinators.Parsec as P
Now I only have to write "P.runPaser", which is much shorter.
Err, I have a beginner question, then: Is there any difference between:
import Very.Long.Module.Name as M
and:
import qualified Very.Long.Module.Name as M
The former lets you access functions from Very.Long.Module.Name also unqualified.
? Loup

On Thu, Jun 5, 2008 at 4:19 PM, Johan Tibell
* Why is this practice common in Haskell
Here are some guesses:
1. It's common in papers. However, papers and libraries are quite different. The former usually build up a small vocabulary and having short names is a big win. Papers rarely make use of the module system at all. The latter are included as pieces of large programs and their names need to be adjusted accordingly.
2. It's the default. You have to add "qualified" to all your imports to make them qualified. In most language imports are qualified by default. I think the latter would have been a better choice but we have to live with the current design so bite the bullet and add those qualified keywords to your imports.
3. Lack of common interfaces. An example would be two different set implementations that essentially have the same interface but since there is no explicitly shared interface, defined using a type class, you sometimes end up with different names. The lack of type families might explain why e.g. collection classes don't share interfaces.
4. Haskell is a very expressive language. You can often write a whole function definition on one line! Adding those module qualifications makes your code slightly longer and it might just break your beautiful one liner into two lines.
Another BIG reason: It's impossible to export a whole hierarchy qualified. I.e it would be neat if the user could write: import Graphics.UI.Gtk And then have Gtk re-export sub-modules qualified, so you could write "Button.new", "Window.new" etc. etc. As it stands you have two options: prefix all the "new" functions with the kind of widget they create (buttonNew, windowNew), or force the user to add a gazillion qualified imports. Ideally you would be able to add "qualified" to the module export statement, and have it automatically bring in that module qualified (it should also support an "as" so you'd write "qualified module Graphics.UI.Gtk.Button as Button" in the export list to get the above behaviour.) -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

On Mon, 9 Jun 2008, Sebastian Sylvan wrote:
Another BIG reason: It's impossible to export a whole hierarchy qualified. I.e it would be neat if the user could write:
import Graphics.UI.Gtk
And then have Gtk re-export sub-modules qualified, so you could write "Button.new", "Window.new" etc. etc. As it stands you have two options: prefix all the "new" functions with the kind of widget they create (buttonNew, windowNew), or force the user to add a gazillion qualified imports.
The problem would be again that no one knows, where "Window" comes from. Better would be import Graphics.UI.Gtk (Window, Button, ) Don't know if this extension would be worth the trouble.

On 6/14/08, Henning Thielemann
On Mon, 9 Jun 2008, Sebastian Sylvan wrote:
Another BIG reason: It's impossible to export a whole hierarchy qualified.
I.e it would be neat if the user could write:
import Graphics.UI.Gtk
And then have Gtk re-export sub-modules qualified, so you could write "Button.new", "Window.new" etc. etc. As it stands you have two options: prefix all the "new" functions with the kind of widget they create (buttonNew, windowNew), or force the user to add a gazillion qualified imports.
The problem would be again that no one knows, where "Window" comes from. Better would be
I really don't see how this is a big problem. Lots of languages do hierarchical import (e.g. .Net languages) and I don't think I've ever heard anyone complain about this particular aspect of it. The worst case scenario is that you need a little bit of tool support to help you sort it out. Plus, it's not like you can't just qualify the import to make it easier to see where it comes from if you really think it's a problem: import qualified Graphics.UI.GTK as GTK and then use GTK.Button.new etc. -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: The problem would be again that no one knows, where "Window" comes from. Better would be
I really don't see how this is a big problem. Lots of languages do hierarchical import (e.g. .Net languages) and I don't think I've ever heard anyone complain about this particular aspect of it.
It's not a problem for you and thus you do not pay attention to these complaints, I suspect. Maybe the people who would complain about the importing style, simply don't use the mentioned languages.
The worst case scenario is that you need a little bit of tool support to help you sort it out. Plus, it's not like you can't just qualify the import to make it easier to see where it comes from if you really think it's a problem:
Cf. http://www.haskell.org/haskellwiki/Import_modules_properly Haskell can re-export modules, which makes tracing identifiers more difficult. I want to be able to read modules without using a tool.

On 6/14/08, Henning Thielemann
On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: The problem would be again that no one knows, where "Window" comes from. Better would be
I really don't see how this is a big problem. Lots of languages do
hierarchical import (e.g. .Net languages) and I don't think I've ever heard anyone complain about this particular aspect of it.
It's not a problem for you and thus you do not pay attention to these complaints, I suspect. Maybe the people who would complain about the importing style, simply don't use the mentioned languages.
The worst case scenario is that you need a little bit of tool support to help you sort it out. Plus, it's not like you can't just qualify the import to make it easier to see where it comes from if you really think it's a problem:
Cf. http://www.haskell.org/haskellwiki/Import_modules_properly
Haskell can re-export modules, which makes tracing identifiers more difficult. I want to be able to read modules without using a tool.
I'm not sure I understand you point. You're so opposed to the *option* of allowing hierarchical exports (even though you can still import it qualified if you personally like having to specify at each callsite exactly where some identifier is coming from), that you'd rather any library making use of a module hierarchy is forced to either make the user add dozens of boilerplate import statements (with "qualified" and "as") or the more common strategy of prefixing each function call with the module name (buttonNew)? To me a module system that requires the latter in practice is horribly broken, and I'm suggesting a low-impact way of fixing it. It may not be the best system available, but it's a tiny extension of the current. I really don't see why adding this option hurts you, when it clearly helps enable doing what this thread advocates (use qualified modules to distinguish between functions of the same name, rather than adding a bunch of prefixes/suffixes to the functions). -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: The problem would be again that no one knows, where "Window" comes from. Better would be
I really don't see how this is a big problem. Lots of languages do
hierarchical import (e.g. .Net languages) and I don't think I've ever heard anyone complain about this particular aspect of it.
It's not a problem for you and thus you do not pay attention to these complaints, I suspect. Maybe the people who would complain about the importing style, simply don't use the mentioned languages.
The worst case scenario is that you need a little bit of tool support to help you sort it out. Plus, it's not like you can't just qualify the import to make it easier to see where it comes from if you really think it's a problem:
Cf. http://www.haskell.org/haskellwiki/Import_modules_properly
Haskell can re-export modules, which makes tracing identifiers more difficult. I want to be able to read modules without using a tool.
I'm not sure I understand you point. You're so opposed to the *option* of allowing hierarchical exports (even though you can still import it qualified if you personally like having to specify at each callsite exactly where some identifier is coming from),
I was concerned with the _import_ part of your proposal. (I haven't thought about the export part so far.)
that you'd rather any library making use of a module hierarchy is forced to either make the user add dozens of boilerplate import statements (with "qualified" and "as") or the more common strategy of prefixing each function call with the module name (buttonNew)? To me a module system that requires the latter in practice is horribly broken, and I'm suggesting a low-impact way of fixing it. It may not be the best system available, but it's a tiny extension of the current.
I really don't see why adding this option hurts you, when it clearly helps enable doing what this thread advocates (use qualified modules to distinguish between functions of the same name, rather than adding a bunch of prefixes/suffixes to the functions).
Button.new is my favorite, because with current import variants I can easily lookup, what Button and Button.new refer to. I understand your proposal in that way that import Graphics.UI.Gtk brings module qualifications Window and Button into scope although they are not explicitly mentioned. Thus I could no longer find out easily what Butten.new means.

On 6/14/08, Henning Thielemann
On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: The problem would be again that no one knows, where "Window" comes from. Better would be
I really don't see how this is a big problem. Lots of languages do
hierarchical import (e.g. .Net languages) and I don't think I've ever heard anyone complain about this particular aspect of it.
It's not a problem for you and thus you do not pay attention to these complaints, I suspect. Maybe the people who would complain about the importing style, simply don't use the mentioned languages.
The worst case scenario is that you need a little bit of tool support to
help you sort it out. Plus, it's not like you can't just qualify the import to make it easier to see where it comes from if you really think it's a problem:
Cf. http://www.haskell.org/haskellwiki/Import_modules_properly
Haskell can re-export modules, which makes tracing identifiers more difficult. I want to be able to read modules without using a tool.
I'm not sure I understand you point. You're so opposed to the *option* of allowing hierarchical exports (even though you can still import it qualified if you personally like having to specify at each callsite exactly where some identifier is coming from),
I was concerned with the _import_ part of your proposal. (I haven't thought about the export part so far.)
that you'd rather any library making use of a module hierarchy is forced
to either make the user add dozens of boilerplate import statements (with "qualified" and "as") or the more common strategy of prefixing each function call with the module name (buttonNew)? To me a module system that requires the latter in practice is horribly broken, and I'm suggesting a low-impact way of fixing it. It may not be the best system available, but it's a tiny extension of the current.
I really don't see why adding this option hurts you, when it clearly helps enable doing what this thread advocates (use qualified modules to distinguish between functions of the same name, rather than adding a bunch of prefixes/suffixes to the functions).
Button.new is my favorite, because with current import variants I can easily lookup, what Button and Button.new refer to. I understand your proposal in that way that
import Graphics.UI.Gtk
brings module qualifications Window and Button into scope although they are not explicitly mentioned. Thus I could no longer find out easily what Butten.new means.
I don't see why this is so bad when it's exactly what we have for other identifiers? E.g. if you import Control.Monad you get mapM, but you can't really say for sure where this identifier comes from, which is no better than not knowing where "Button.new" comes from. In both cases you have the option to qualify the module import so you have to say "Monad.mapM" or "GTK.Button.new" which makes it more apparent. I suppose you would make the "hiding" clause and the "import list" thing work with modules too for consistency, so if you really wanted to you could list the modules/identifiers that you bring in. Are you saying that you prefer the situation where to use GTK the user would have to explicitly import every single sub-module in the hierarchy ("import qualified Graphics.UI.GTK.X as X" where X = {Button,Window, ... etc})? I don't think that's very nice at all, and I certainly don't like having to add the module name to the functions... I think lots of libraries are like that, and we need some mechanism of importing lots of related modules together so that they come in qualified, without forcing the user to write a gazillion lines of boilerplate import statements.. I think that if GTK did use this system (rather than append the module name to the function and export them "flatly") a lot of people would resort to ugly hacks like putting the import statements in a file somewhere and using the C preprocessor to include it, yuck! (OTOH this may be just what's required to convince everyone that we need to improve the module system)... -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: On Sat, 14 Jun 2008, Sebastian Sylvan wrote:
On 6/14/08, Henning Thielemann
wrote: The problem would be again that no one knows, where "Window" comes from. Better would be
I really don't see how this is a big problem. Lots of languages do
hierarchical import (e.g. .Net languages) and I don't think I've ever heard anyone complain about this particular aspect of it.
It's not a problem for you and thus you do not pay attention to these complaints, I suspect. Maybe the people who would complain about the importing style, simply don't use the mentioned languages.
The worst case scenario is that you need a little bit of tool support to
help you sort it out. Plus, it's not like you can't just qualify the import to make it easier to see where it comes from if you really think it's a problem:
Cf. http://www.haskell.org/haskellwiki/Import_modules_properly
Haskell can re-export modules, which makes tracing identifiers more difficult. I want to be able to read modules without using a tool.
I'm not sure I understand you point. You're so opposed to the *option* of allowing hierarchical exports (even though you can still import it qualified if you personally like having to specify at each callsite exactly where some identifier is coming from),
I was concerned with the _import_ part of your proposal. (I haven't thought about the export part so far.)
that you'd rather any library making use of a module hierarchy is forced
to either make the user add dozens of boilerplate import statements (with "qualified" and "as") or the more common strategy of prefixing each function call with the module name (buttonNew)? To me a module system that requires the latter in practice is horribly broken, and I'm suggesting a low-impact way of fixing it. It may not be the best system available, but it's a tiny extension of the current.
I really don't see why adding this option hurts you, when it clearly helps enable doing what this thread advocates (use qualified modules to distinguish between functions of the same name, rather than adding a bunch of prefixes/suffixes to the functions).
Button.new is my favorite, because with current import variants I can easily lookup, what Button and Button.new refer to. I understand your proposal in that way that
import Graphics.UI.Gtk
brings module qualifications Window and Button into scope although they are not explicitly mentioned. Thus I could no longer find out easily what Butten.new means.
I don't see why this is so bad when it's exactly what we have for other identifiers? E.g. if you import Control.Monad you get mapM, but you can't really say for sure where this identifier comes from, which is no better than not knowing where "Button.new" comes from. In both cases you have the option to qualify the module import so you have to say "Monad.mapM" or "GTK.Button.new" which makes it more apparent.
I suppose you would make the "hiding" clause and the "import list" thing work with modules too for consistency, so if you really wanted to you could list the modules/identifiers that you bring in.
yeah, we could come up with a syntax. one that gives privileged meaning to hierarchy. If used according to "design your modules for qualified import", it would still allow fairly easy use and looking up function uses. import Graphics.UI.GTK (import qualified Button, import qualified Window) then you get Button.f (because Graphics.UI.GTK wasn't imported qualified), Graphics.UI.GTK.Button.f, (not f or Graphics.UI.GTK.f because of qualified Button) ... they're normal import statements inside. What it saves is the duplication of Graphics.UI.GTK and "....Button as Button". Not sure I like how long "import qualified" is, repeated there, but it seemed much less confusing than anything shorter. import Data (import qualified Map, Map.Map) or import Data (import qualified Map, import Map(Map)) or a shortcut for that common pattern of importing a few things unqualified import Data (import qualified Map and (Map)) aka. import qualified Data.Map as Map and (Map) aka. import qualified Data.Map as Map (empty,singleton,...) and (Map) or perhaps "unqualifying" rather than "and" personally I would like it if we could also import (f as g) if we wanted to rename an "f" we were importing, to "g" in the module and re-exports, without having to be concerned about (for lowercase) monomorphism restriction, (for types) whether a synonym will work properly everywhere (not without extensions!), (for constructor, record fields, and classes) simple *impossibility*. That wish is only related in that it's a related generalization, though. hmm. -Isaac
Are you saying that you prefer the situation where to use GTK the user would have to explicitly import every single sub-module in the hierarchy ("import qualified Graphics.UI.GTK.X as X" where X = {Button,Window, ... etc})? I don't think that's very nice at all, and I certainly don't like having to add the module name to the functions... I think lots of libraries are like that, and we need some mechanism of importing lots of related modules together so that they come in qualified, without forcing the user to write a gazillion lines of boilerplate import statements..
I think that if GTK did use this system (rather than append the module name to the function and export them "flatly") a lot of people would resort to ugly hacks like putting the import statements in a file somewhere and using the C preprocessor to include it, yuck! (OTOH this may be just what's required to convince everyone that we need to improve the module system)...
------------------------------------------------------------------------
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sat, 14 Jun 2008, Isaac Dupree wrote:
yeah, we could come up with a syntax. one that gives privileged meaning to hierarchy. If used according to "design your modules for qualified import", it would still allow fairly easy use and looking up function uses.
import Graphics.UI.GTK (import qualified Button, import qualified Window)
then you get Button.f (because Graphics.UI.GTK wasn't imported qualified), Graphics.UI.GTK.Button.f, (not f or Graphics.UI.GTK.f because of qualified Button) ... they're normal import statements inside. What it saves is the duplication of Graphics.UI.GTK and "....Button as Button". Not sure I like how long "import qualified" is, repeated there, but it seemed much less confusing than anything shorter.
import Data (import qualified Map, Map.Map) or import Data (import qualified Map, import Map(Map)) or a shortcut for that common pattern of importing a few things unqualified import Data (import qualified Map and (Map)) aka. import qualified Data.Map as Map and (Map) aka. import qualified Data.Map as Map (empty,singleton,...) and (Map) or perhaps "unqualifying" rather than "and"
personally I would like it if we could also import (f as g) if we wanted to rename an "f" we were importing, to "g" in the module and re-exports, without having to be concerned about (for lowercase) monomorphism restriction, (for types) whether a synonym will work properly everywhere (not without extensions!), (for constructor, record fields, and classes) simple *impossibility*. That wish is only related in that it's a related generalization, though.
nice

On Sat, 2008-06-14 at 19:21 +0100, Sebastian Sylvan wrote:
I think that if GTK did use this system (rather than append the module name to the function and export them "flatly") a lot of people would resort to ugly hacks like putting the import statements in a file somewhere and using the C preprocessor to include it, yuck! (OTOH this may be just what's required to convince everyone that we need to improve the module system)...
Right. That's exactly why we've not done something like that. With 100+ modules in the Gtk package it's totally infeasible to do qualified imports of them all. If we get a proper way to export a non-flat namespace then Gtk2Hs will certainly switch to using it. Using 'buttonBlah' is horrible but there is currently nothing better. There have been a few suggestions along these lines. Check the archives. I'm not sure what is proposed for haskell', probably nothing since nothing is currently implemented and we're only supposed to be standardising existing practise. Duncan

Am Sonntag, 15. Juni 2008 23:17 schrieb Duncan Coutts:
[…]
If we get a proper way to export a non-flat namespace then Gtk2Hs will certainly switch to using it. Using 'buttonBlah' is horrible but there is currently nothing better.
So is there anyone who wants to file a feature request?
[…]
Best wishes, Wolfgang

Duncan Coutts wrote:
Right. That's exactly why we've not done something like that. With 100+ modules in the Gtk package it's totally infeasible to do qualified imports of them all.
If we get a proper way to export a non-flat namespace then Gtk2Hs will certainly switch to using it. Using 'buttonBlah' is horrible but there is currently nothing better.
okay, it's horrible! It's no more manually-traceable than anything else either, if you just import Gtk2Hs unqualified. Is there any way it could possibly be acceptably concise *and* traceable? let's see If "GTK" appears in every usage (e.g. GTK.buttonBlah, gtkButtonBlah...), probably not at all concise enough for GUI code! But if it doesn't, then we would need at minimum to list each of those ones that we used (probably not all 100 of them). It couldn't get any more concise than this to use Button.blah etc.: import GTK.modules (Button, Window, ...) never mind the exact syntax yet -- is listing them acceptable? (and if there are so many, is it practically traceable by humans anyway? Perhaps we're assuming that these humans at least have "search this file" editor-capabilities?) Are there multiple "blah" functions among the GTK modules? I.e. would GTK.blah be unambiguous, not mentioning that it's a button function. (And would it be too confusing not to mention that it's a button function...) If it would be ambiguous, would typeclasses work to fix that (or renaming functions that have no good reason to have the same name, or occasionally including blahButton sort of names)? If 100 modules is too much, would it be a reasonable compromise between clarity and conciseness to export coarser-grained, so there are only maybe half a dozen GTK modules that your typical program imports?
There have been a few suggestions along these lines. Check the archives. I'm not sure what is proposed for haskell', probably nothing since nothing is currently implemented and we're only supposed to be standardising existing practise.
I had trouble in my first attempt to search the archives... Googling for "import" in haskell-cafe found too much code, and my personal e-mail records back to March 2007 found nothing else relevant with "import" in the title. -Isaac

Hello Isaac, Monday, June 16, 2008, 4:02:10 PM, you wrote:
Are there multiple "blah" functions among the GTK modules? I.e. would GTK.blah be unambiguous, not mentioning that it's a button function.
yes. actually, gtk2hs uses typeclasses to overload functions over various types -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Duncan Coutts wrote:
If we get a proper way to export a non-flat namespace then Gtk2Hs will certainly switch to using it. Using 'buttonBlah' is horrible but there is currently nothing better.
Whilst I'm sure anyone who's used deep module structures has wondered about this feature, I've seen no serious proposal of any kind. Does anyone know what this should look like? Jules

Duncan Coutts wrote:
If we get a proper way to export a non-flat namespace then Gtk2Hs will certainly switch to using it. Using 'buttonBlah' is horrible but there is currently nothing better.
Whilst I'm sure anyone who's used deep module structures has wondered about this feature, I've seen no serious proposal of any kind.
google for "haskell package mounting" or "haskell package grafting". Perhaps the discussion has appeared under other keywords, but those are the ones that spring to mind. Claus
participants (22)
-
Achim Schneider
-
Adam Vogt
-
ajb@spamcop.net
-
Andrew Coppin
-
Bulat Ziganshin
-
Claus Reinke
-
Dan Doel
-
Daniel Fischer
-
Denis Bueno
-
Duncan Coutts
-
Henning Thielemann
-
Isaac Dupree
-
Jan-Willem Maessen
-
Johan Tibell
-
Jules Bean
-
Ketil Malde
-
Loup Vaillant
-
Nicolas Pouillard
-
Peter Hercek
-
Sebastian Sylvan
-
Wolfgang Jeltsch
-
Xiao-Yong Jin