Re: Library conventions
Hello! On Fri, Jun 23, 2000 at 09:52:53AM -0700, Mark P Jones wrote: [...] Hugs is also quite old; it's core goes back nearly ten years! With a more "modern" interface, we might solve the interface dilemma by arranging for fully qualified names, types, etc. to pop up in a "tooltip" when the user mouses over an identifier in an error message. Perhaps other people can suggest more modest proposals for making intelligent choice of qualifying prefixes that would fit in more directly with the existing framework. Please don't make hugs into a Windows only thingy (or X only, for that respect). While I don't do real projects with Haskell, I still like using hugs from the OpenBSD text console (or screen or a remote login). So also please don't make reasonable usage dependant on graphics. [...] developers to get the job done on their own. I'm convinced that the only way we will ever have truly excellent tools is by working on them together as a community. That's true in principle, however not everyone doing things with Haskell are able to grok something like the ghc source code; when I tried reading some of it, I didn't understand very much, even though I've read some papers about ghc's translation techniques, just for an example. Yes, I might find the hugs source easier to understand, however there's a significant threshold even there, I think. All the best, Mark The same for you and all other implementors and Haskellers. Kind regards, Hannah.
Re: Library conventions
Using `Left' and `Right' for such cases is fundamentally confusing since it is not clear what the meaning of `Left' and `Right' is. Well, I don't totally agree. Anyone using Right for Wrong deserves to have his/her head examined. :) -- Lennart
Re: Library conventions
On Tue, 27 Jun 2000, Lennart Augustsson wrote: Using `Left' and `Right' for such cases is fundamentally confusing since it is not clear what the meaning of `Left' and `Right' is. Well, I don't totally agree. Anyone using Right for Wrong deserves to have his/her head examined. :) I probably deserve to have my head examined for different reasons :), but lots of my code uses Left - ok result, Right - error indication and I'm a native english speaker. I think the reason is the same reason non-native english speakers don't complain about how the keywords/ubiquitous `words' in virtually every programming language are all english terms: very quickly they just become abstract symbols based on how they look/are typed without any connection to the natural language they were drawn from. (I've always been puzzled by the choice of Left and Right, which imply symmetry, when at least in the programs I write, Primary Secondary would fit the usage better since if there is general symmetry rather than a `desirability ordering' that's almost always done in a new datatype.) ___cheers,_dave www.cs.bris.ac.uk/~tweed/pi.htm|I shoulda realised building the email: [EMAIL PROTECTED] |memory allocation subsytem with work tel: (0117) 954-5253 |--with-malicious-ai was a bad idea.
Re: Library conventions
Lennart Augustsson writes: Using `Left' and `Right' for such cases is fundamentally confusing since it is not clear what the meaning of `Left' and `Right' is. Well, I don't totally agree. Anyone using Right for Wrong deserves to have his/her head examined. :) Unless you're left-handed of course (:-) --Thomas (sometimes left-handed)
Re: Library conventions
Jon Fairbairn wrote: Am I alone in thinking that the prelude is desperately in need of restructuring? No. Personally I think it should be got rid of entirely, or rather trimmed down to the absolute bare minimum required for the syntax. By the way I think Sven's proposals are thoroughly excellent. I don't agree with those who say that empty sets, empty maps and so on should all have the same name, distinguished only by module. This is just too inconvenient. Lennart Augustsson writes: If I want to switch from FooTree to BarTree I have to change all over the code Well I think the solution to this is to make the name for the empty object "emptyXXX" (and the type name itself) only encode the functionality provided. Thus all balanced trees (or anything which provides a reasonable mapping function on an Ordered type) should have the same type name and "emptyXXX" name. If you want to change from one sort of balanced tree to another you only have to change the import declaration. If you want a more fundamental change, say between hash tables and balanced trees, then you WILL have to go through changing emptyXXX to emptyYYY (if you don't want the quick hack of saying "import YYY;emptyXXX=emptyYYY") but since the functionality has changed I think you should have to anyway.
Re: Library conventions
Frank Atanassow [EMAIL PROTECTED] wrote, Chris Okasaki writes: If anybody has a good argument against using the module system in this context, I would very much like to hear it, because I use the module-based convention almost exclusively in Edison. To be fair, I can give 4 arguments against it. [..] 3) Nobody else uses it either, except me (and Chris, apparently :). [..] HOpenGL uses it and Gtk+HS is moving the same way. (And this although the C libraries on which these Haskell libraries are based use prefixes as poor man's name spaces.) Manuel
Re: Library conventions
Jon Fairbairn [EMAIL PROTECTED] wrote, 4) Qualified infix operators are ugly. Yes, I can't deny that. :) That seems like a presentation problem. One day an editor might be persuaded to display Prelude.+ as (till ex.) + in proper size and 'Prelude' in smaller type beneath it or as a subscript. You can't base the design of a general purpose programming language on the capabilities of one (or even some) editor(s). Sometimes I am editing Haskell over a remote login connection, which leaves me more or less with plain ascii. Manuel
RE: Library conventions
"Mark P Jones" [EMAIL PROTECTED] wrote, I'm convinced that the only way we will ever have truly excellent tools is by working on them together as a community. Very true! Manuel
Re: Library conventions
Fri, 23 Jun 2000 23:58:36 +0200, Sven Panne [EMAIL PROTECTED] pisze: stToIO is a misnomer (should be sTToIO), stToIO looks better for me. What about declaring that lowercasing the first letter of an abbreviation consisting of only capital letters is realized by lowercasing the whole word? Including ioRefToFoo. e.g. proposals for the names of non-monadic versions of updateBlah, Edison uses update :: Seq s = Int - a - s a - s a adjust :: Seq s = (a - a) - Int - s a - s a for what my guidelines could give setElem:: Seq s = s a - Int - a - s a updateElem :: Seq s = s a - Int - (a - a) - s a Not that I don't like partial application, but Edison's order is usually not used elsewhere, e.g. in PosixTTY (using "with" prefix instead of my "set"), Bits (using separate setBit and clearBit instead of setBit with Bool parameter, and complementBit instead of updateBit - but the latter is OK), FiniteMap. Maybe we should promote Edison's order, which is consistent with module List, but what about above libraries? -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
Re: Library conventions
Marcin 'Qrczak' Kowalczyk wrote: stToIO looks better for me. What about declaring that lowercasing the first letter of an abbreviation consisting of only capital letters is realized by lowercasing the whole word? [...] OK, this makes sense and the rule is not much more complicated. e.g. proposals for the names of non-monadic versions of updateBlah, Edison uses update :: Seq s = Int - a - s a - s a adjust :: Seq s = (a - a) - Int - s a - s a for what my guidelines could give setElem:: Seq s = s a - Int - a - s a updateElem :: Seq s = s a - Int - (a - a) - s a Not that I don't like partial application, but Edison's order is usually not used elsewhere, [...] Please note that at least since the hslibs shipped with GHC 4.06, the `update' prefix has been taken by actions (namely updateIORef, which has accompanied by an updateSTRef lately). I'm a little bit reluctant to propose it for a different usage now. Edison uses it in neither way. :-( But we could use Edison's `adjust' for the non-monadic case. Bits (using separate setBit and clearBit instead of setBit with Bool parameter, and complementBit instead of updateBit - but the latter is OK) [...] Well, Bits is IMHO an example for a module which is completely messed up: Totally inconsistent naming, too many methods, etc. Perhaps I'm grumbling about this in a different mail. :-) Maybe we should promote Edison's order, which is consistent with module List, but what about above libraries? Aaaah, finally something which has nothing to do with names. :-) I don't have a clear picture about common practice regarding argument order. Any ideas for simple rules which cover most cases? Remember: This is not a futile attempt to prescribe everyone how to do things. But remembering the argument order for the tons of functions within hslibs without peeking into the respective docs is currently not easy, so an easy convention would be nice here. Cheers, Sven
Re: Library conventions
Sat, 24 Jun 2000 14:34:37 +0200, Sven Panne [EMAIL PROTECTED] pisze: Please note that at least since the hslibs shipped with GHC 4.06, the `update' prefix has been taken by actions (namely updateIORef, which has accompanied by an updateSTRef lately). I'm a little bit reluctant to propose it for a different usage now. I too prefer distinguishing similar operations that differ in monadness, to avoid silly mistakes that may make some people feel "stupid Haskell forces me to remember what is monadic and what is not, what a silly distinction". But it's hard to do all the time anyway (e.g. isX, setX), so some exceptions should not hurt much. For updating we have: update, modify, adjust. I proposed modify for the monadic case, because IMHO it sounds most imperatively and better than update suggests that the old value is used. You changed it to update. OK, I have not strong feelings for modify. Monadic modify is used in MonadState. Monadic update is used in {IO,ST}Ref. Pure adjust is used in Edison. Something like pure update is produced by DrIFT. I have not found more in lib/std or hslibs. I don't have a clear picture about common practice regarding argument order. Any ideas for simple rules which cover most cases? For functions that take an old version of something plus some modifiers and return a new version, current practice is inconsistent. Old version is the first argument: (Array.//) FiniteMap Bits PosixTTY plusAddr Old version is a middle argument: Array.accum Old version is the last argument: Prelude.fmap List Array.ixmap MonadState Edison PackedString Maybe we should promote the last argument, while stating that for historical reasons it is not always used... Rationale for the last argument: partial application of course, using layout where the old value is complex and modifiers are simple, and applying many modifications at once (the last case works for the first argument variant only when there is exactly one other argument, so the function name can be put in backquotes). Some other rules. When a function takes a state and returns a pair consisting of some result and an updated state, the result should be first and the state should be second. Seems to be consistently used (Random, MonadState). When an Either result encodes a good result or an error, the error should be Left and the good result should be Right. Rationale: partially applied type is a good Functor and Monad. Seems to be consistently used (MonadEither, Parsec). Edison's documentation contains various argument order rules. I am trying to make an unified system of classes that would catch three Edison's families: sequences, collections and associations. And maybe the fourth that does not fit into these and is missing: arrays. It's hard and complex :-( Results are less ugly when functional dependencies are used, but I still cannot keep the whole functionality of current Edison. The problem is that if element type is going to the context, then it's impossible to have methods like current intersectWith :: FiniteMapX m k = (a-b-c) - m k a - m k b - m k c -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
Re: Library conventions
Edison uses update :: Seq s = Int - a - s a - s a adjust :: Seq s = (a - a) - Int - s a - s a for what my guidelines could give setElem:: Seq s = s a - Int - a - s a updateElem :: Seq s = s a - Int - (a - a) - s a Not that I don't like partial application, but Edison's order is usually not used elsewhere, e.g. in PosixTTY (using "with" prefix instead of my "set"), Bits (using separate setBit and clearBit instead of setBit with Bool parameter, and complementBit instead of updateBit - but the latter is OK), FiniteMap. Maybe we should promote Edison's order, which is consistent with module List, but what about above libraries? Simon PJ sold me on this order, which supports multiple updates like update 1 'a' $ update 2 'b' $ update 3 'c' s instead of update (update (update 3 'c' s) 2 'b) 1 'a' Chris
Re: Library conventions
24 Jun 2000 13:54:49 GMT, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] pisze: I am trying to make an unified system of classes that would catch three Edison's families: sequences, collections and associations. And maybe the fourth that does not fit into these and is missing: arrays. It's hard and complex :-( Results are less ugly when functional dependencies are used, but I still cannot keep the whole functionality of current Edison. Seems that it would get simpler if association maps were expressed as collections of key:=value pairs (with Eq,Ord instances ignoring the value component). Association maps would have extra functions, but they could be always treated as appropriate collections of such pairs. Is this idea fundamentally broken for some reason? Advantages: simpler interface, and that concrete collections can easily provide association maps (those extra functions would be methods with default implementations). Names for association maps would get rotated. E.g. instead of separate Collection.minElem :: OrdColl c a = c a - a Assoc.minElem:: OrdAssocX m k = m k a - a Assoc.minElemWithKey :: OrdAssoc m k = m k a - (k,a) there would be single Collection's minElem with a special case being equivalent to current Assoc.minElemWithKey, and a separate minValue for association maps that returns only the value. Seems that an extended form of context could be useful. E.g. (forall a. Coll c a) = ... means that c is constrained to types for which there exists an appropriate instance that works for all types a. Is this a good idea? Is it possible/easy to implement? -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
Re: Library conventions
Seems that it would get simpler if association maps were expressed as collections of key:=value pairs (with Eq,Ord instances ignoring the value component). Association maps would have extra functions, but they could be always treated as appropriate collections of such pairs. Is this idea fundamentally broken for some reason? I considered this for Edison but rejected in for two reasons. First, it constrains the implementation, adding an extra level of indirection to every access. Second, and more seriously, it moves the unconstrained type variable into the class, which leads to several potential problems such as more ambiguity messages. Your idea below would take care of at least some of these problems. Seems that an extended form of context could be useful. E.g. (forall a. Coll c a) = ... means that c is constrained to types for which there exists an appropriate instance that works for all types a. Chris
Re: Library conventions
Sat, 24 Jun 2000 13:10:24 -0400 (EDT), Chris Okasaki [EMAIL PROTECTED] pisze: I considered this for Edison but rejected in for two reasons. First, it constrains the implementation, adding an extra level of indirection to every access. It does not, if extra functions for association maps are methods themselves, instead of always going through generic functions on (:=) pairs. This means that collections would still need to get some trivial instances to be used as maps. Second, and more seriously, it moves the unconstrained type variable into the class, which leads to several potential problems such as more ambiguity messages. Indeed. I'm not sure know how big the problem is... OTOH I can imagine types that need these constraints: sequences of bits, packed strings of characters, containers shared with foreign languages. IArray does constrain elements and has unboxed arrays as instances. It seems impossible to unify things that currently share names, without either constraints on elements or contexts with local foralls :-( -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
Re: Library conventions
Sven Panne [EMAIL PROTECTED] wrote, Marcin 'Qrczak' Kowalczyk wrote: stToIO looks better for me. What about declaring that lowercasing the first letter of an abbreviation consisting of only capital letters is realized by lowercasing the whole word? [...] OK, this makes sense and the rule is not much more complicated. That's indeed also what I usually do. Manuel
Re: Library conventions
[EMAIL PROTECTED] (Marcin 'Qrczak' Kowalczyk) wrote, Sat, 24 Jun 2000 14:34:37 +0200, Sven Panne [EMAIL PROTECTED] pisze: I don't have a clear picture about common practice regarding argument order. Any ideas for simple rules which cover most cases? For functions that take an old version of something plus some modifiers and return a new version, current practice is inconsistent. Old version is the first argument: (Array.//) FiniteMap Bits PosixTTY plusAddr Old version is a middle argument: Array.accum Old version is the last argument: Prelude.fmap List Array.ixmap MonadState Edison PackedString Maybe we should promote the last argument, while stating that for historical reasons it is not always used... Rationale for the last argument: partial application of course, using layout where the old value is complex and modifiers are simple, and applying many modifications at once (the last case works for the first argument variant only when there is exactly one other argument, so the function name can be put in backquotes). I just scanned through some of my code and it seems that I relatively consistently place the old version as the first argument in my libraries. Indeed one of the few places where I used the last argument is my finite map implementation and I am always messing up the arguments of these functions when I use them. In fact, I think, one reason that makes it difficult to find a single rule here is because we essentially two different classes of functions: (1) Functions describing a generic traversal of a data structure (like the well know list functions map, foldr, etc). (2) Functions modelling state updates (eg, entering elements into a finite map etc). In the first case, partial applications are often very useful, which promotes the use of the last argument for the traversed data structure. In contrast, state updates (ie, functional state transformers) feel more natural when the modified structure is the first argument. Reasons for this are probably that this is the convention that we are used to from imperative and oo languages, and furthermore, when reading a program containing such functions, the most important question is `which structure is modified', and then, we check how the structure is modified exactly. Manuel
Re: Library conventions
Chris Okasaki wrote: I've taken a look at these. I'll limit myself to just one comment: 1.1.1. Constructor names Empty values of type X have the name emptyX, e.g. emptySet. You've struck a pet peeve of mine. These suffixes are doing namespace management, avoiding name clashes between different things that you want to call empty. But Haskell already has a perfectly good language mechanism for doing this -- the module system! Why is emptyX preferable to X.empty? The latter convention is much more flexible. I agree 100% with Chris. Having the type as a suffix just gives you poor maintainability of the code. If I want to switch from FooTree to BarTree I have to change all over the code, whereas with an `import .. as X' and X.empty I only have to change in one place. -- -- Lennart
Re: Library conventions
Frank Atanassow wrote: To be fair, I can give 4 arguments against it. 1) Hugs's error messages don't qualify names, so they become very difficult to read when you use this convention. That's a totally bogus reason. Tell the implementors to fix Hugs. 2) The Prelude doesn't use it. Well, it doesn't for historical reasons. 3) Nobody else uses it either, except me (and Chris, apparently :). I do. I think many people do. The libraries that come with HBC uses it. 4) Qualified infix operators are ugly. Yes, I can't deny that. :) -- -- Lennart
Re: Library conventions
"chris" == Chris Okasaki [EMAIL PROTECTED] writes: chris You've struck a pet peeve of mine. These suffixes are doing namespace chris management, avoiding name clashes between different things that you chris want to call empty. But Haskell already has a perfectly good language chris mechanism for doing this -- the module system! Why is emptyX preferable chris to X.empty? The latter convention is much more flexible. It allows the chris user to I completely agree with chris in this point. Later, Juan. -- In theory, practice and theory are the same, but in practice they are different -- Larry McVoy
Re: Library conventions
Lennart Augustsson wrote: Frank Atanassow wrote: 2) The Prelude doesn't use it. Well, it doesn't for historical reasons. Am I alone in thinking that the prelude is desperately in need of restructuring? Has anyone got any proposals for nested modules (so we could have Prelude.List.head)? 3) Nobody else uses it either, except me (and Chris, apparently :). I do. I think many people do. I would if I needed it. 4) Qualified infix operators are ugly. Yes, I can't deny that. :) That seems like a presentation problem. One day an editor might be persuaded to display Prelude.+ as (till ex.) + in proper size and 'Prelude' in smaller type beneath it or as a subscript. Jón -- Jón Fairbairn [EMAIL PROTECTED] 18 Kimberley Road[EMAIL PROTECTED] Cambridge CB4 1HH+44 1223 570179 (after 14:00 only, please!)
RE: Library conventions
| 1) Hugs's error messages don't qualify names, so they become | very difficult to read when you use this convention. | ... | ... #1 is the least important in theory, since it's fixable and | implementation-dependent, but turned out for me to be the most | important in practice; Hugs' atrocious behavior on this score has | caused me to disregard my own better judgement here for serious | projects. Despite the way that many people use it, and even with all the changes that have been made to it, Hugs simply wasn't designed for "serious projects". It was intended for small projects, and as a tool for education and research. Using qualified names in error messages can make things unnecessarily harder to read in such contexts like that. As an expert user working on large projects, your perspective is different. But I don't think the design choices are as clear cut as you suggest. Hugs is also quite old; it's core goes back nearly ten years! With a more "modern" interface, we might solve the interface dilemma by arranging for fully qualified names, types, etc. to pop up in a "tooltip" when the user mouses over an identifier in an error message. Perhaps other people can suggest more modest proposals for making intelligent choice of qualifying prefixes that would fit in more directly with the existing framework. A final comment: don't forget that you have full access to the source code for Hugs, and hence the opportunity not just to identify weaknesses, but also to fix them, and to share the results so that everyone benefits! The same goes for all of our Haskell systems, not just Hugs. There just aren't enough developers to get the job done on their own. I'm convinced that the only way we will ever have truly excellent tools is by working on them together as a community. All the best, Mark
Re: Library conventions
Fri, 23 Jun 2000 09:05:54 -0400 (EDT), Chris Okasaki [EMAIL PROTECTED] pisze: These suffixes are doing namespace management, avoiding name clashes between different things that you want to call empty. But Haskell already has a perfectly good language mechanism for doing this -- the module system! Why is emptyX preferable to X.empty? The latter convention is much more flexible. I prefer recognizing common interfaces and making appropriate classes. It is more convenient and more flexible than qualified imports: * More than one type can be used unqualified at the same time. * The same function will work for different types. * Adding a new implementation will get some derived functions and default methods for free. * Different types need not be exported by separate modules. * Interfaces of derived modules will be overloaded instead of being tied to particular implementation. Imagine what happens when one module produces a set implemented as SetX and another expects a set implemented as SetY. We don't have parametrized modules. I don't like modules that have to be imported qualified. -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
RE: Library conventions
On Fri, 23 Jun 2000, Mark P Jones wrote: [snip] Hugs is also quite old; it's core goes back nearly ten years! With a more "modern" interface, we might solve the interface dilemma by arranging for fully qualified names, types, etc. to pop up in a "tooltip" when the user mouses over an identifier in an error message. Perhaps other people can suggest more modest proposals for making intelligent choice of qualifying prefixes that would fit in more directly with the existing framework. One approach that seems to work quite well (and which I have used), is to keep note of all the names that are currently in use, and whenever a name is displayed, qualify it enough to distinguish it from all other names that could occur. [snip] -- Robert Ennals - 0798-904-3486 - http://thor.cam.ac.uk/~rje33/
Re: Library conventions
23 Jun 2000 16:57:48 GMT, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] pisze: * [...] * Overloading by the monad (like MArray) allows adding instances for derived monads, without explicit lifting on each use. -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
Re: Library conventions
These suffixes are doing namespace management, avoiding name clashes between different things that you want to call empty. But Haskell already has a perfectly good language mechanism for doing this -- the module system! Why is emptyX preferable to X.empty? The latter convention is much more flexible. I prefer recognizing common interfaces and making appropriate classes. It is more convenient and more flexible than qualified imports: [...reasons deleted...] But classes and qualified imports are not in competition! Suppose you have two *classes* that both need/want the same name. For example, you may have a class of sequences and a class of finite maps that both want to use an empty method. Do you call one emptyS and the other emptyFM? Or do you disambiguate using qualified names? You might say, "Neither! Make a common superclass containing empty and anything else common to both sequences and finite maps." Unfortunately, this doesn't work because type constructors for sequences and finite maps both have different kinds and different constraints on their elements. I don't like modules that have to be imported qualified. Can you be more specific? I understand that you don't want to use qualified names in those situations where a class would be a better solution, but what about when classes alone don't solve the problem? Chris
Re: Library conventions
Fri, 23 Jun 2000 14:11:04 -0400 (EDT), Chris Okasaki [EMAIL PROTECTED] pisze: Suppose you have two *classes* that both need/want the same name. For example, you may have a class of sequences and a class of finite maps that both want to use an empty method. Do you call one emptyS and the other emptyFM? Or do you disambiguate using qualified names? You might say, "Neither! Make a common superclass containing empty and anything else common to both sequences and finite maps." Depends on if there is a chance that the same piece of code would be used for any of these types, disambiguated by a decision taken elsewhere. If yes, I would try to put them in a single class. If not, and if making a class just for overloading looks silly, unfortunately people have different opinions whether to add suffixes or use qualified names. Unfortunately, this doesn't work because type constructors for sequences and finite maps both have different kinds and different constraints on their elements. It does work in this case: classHasEmpty c where empty :: c instance HasEmpty [a] where empty = [] instance HasEmpty (FiniteMap k v) where empty = emptyFM If constraints were needed here, they could be easily added to instance contexts. I don't like modules that have to be imported qualified. Can you be more specific? If some names clash with other modules, there is a tendence to import the whole module qualified instead of deciding individually, remembering which names can be used unqualified. Then some names are unnecessarily long. Not all modules provide only a type with operations on it. The module Concurrent provides several kinds of references and streams. Some of them are reexported from other modules, but QSem and QSemN both originate from module Semaphore. If waitQSem :: QSem - IO () waitQSemN :: QSem - Int - IO () were to share a single name, they would have to be split to two modules and imported separately instead of by just "import Concurrent". Maybe even the interface of semaphores could be overloaded, although it does not give much. wait :: Semaphore s = s - IO () would be defined as waitQSem or \s - waitQSemN s 1, and waitN :: SemaphoreN s = s - Int - IO () would have only one instance among types provided: waitQSemN. If somebody wanted to share a semaphore with another language (provided that concurrency eventually works for foreign calls), a foreign binding to a foreign semaphore would make another instance. I don't mind using short names and accidental clash for the name "wait" between independent modules rarely used together, but I think that Haskell modules are not good in parametrizing by large pieces of code. I treat the import list as the function of entities used in the module, not the opposite. -- __(" Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/ \__/GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E- ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t QRCZAK5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-
Re: Library conventions
I *knew* people couldn't resist talking about names! :-) OK, I've invited you to do this, but more than a dozen mails solely about the first item of section 1.1.1 were a little bit surprising... To be more serious: Perhaps I wasn't clear enough about the purpose of these conventions. What they're trying to describe is current practice in hslibs, not what would be the best thing if they were rewritten from scratch. Note that hslibs currently contains about 100 modules, and there are probably lots of programs out there using this library collection. Making fundamental changes like the replacement of suffixes by qualification would break almost every single program using hslibs. I doubt that a lot of people would cheerfully change most of their programs they've written, not to mention the heart attack SPJ would probably suffer... ;-) I remember the tons of mails on the developer lists about an extremely simple change (to the inaugurated: makeForeignObj). Personally, I'm not a true believer in this whole prefixing/suffixing business either. I've silently dropped the rl_ prefix from the names in the Readline lib, nuked the gl/glu/glut prefix in my HOpenGL binding, etc. But these were either seldom used or completely new libs, you can't do this for hslibs in general. If we were living in a better world, Haskell would have a more expressive module system (i.e. parameterized, first class modules in non-flat name-space, etc.) and people would have used it correctly from the start. But alas, we have to live with the current state of things, at least for H98. For Haskell 2 there should probably be a hslibs 2, too, incorporating what we've learned from the design of the H98 libs. To be more concrete: Although Set.empty vs. emptySet or IORef.update vs. updateIORef seem to have some advantages, but things are not always that simple: What about e.g. the xToY convention? Or getEnv? (The environment is not a separate type, much less an own module.) And what about Integer.to? (Even if there was a module Integer, I'd prefer toInteger.) It seems that we have to live with prefixes/suffixes in one way or the other. And note that even in their current (probably non-perfect) form the conventions are of some use: They state clearly that e.g. readIORef is the correct name (not getIORef), updateIORef returns (), stToIO is a misnomer (should be sTToIO), makeStablePtr should better be named newStablePtr, etc. Making a careful transition to a consistent scheme within hslibs is likely to be non-trivial amount of work. What I was hoping to get were some less drastic improvements of the conventions, e.g. proposals for the names of non-monadic versions of updateBlah, some guidelines when a type should live in its own module, etc. Cheers, Sven
Re: Library conventions
On Fri, 23 Jun 2000, Chris Okasaki wrote: (...) Also, I've noticed a tendency to shorten the suffixes as much as possible (eg, emptyS or emptyFM), in which case you again quickly run into name clashes. (...) I agree, that is undesirable. Such names get cryptic and are usually overlooked when searching for "stuff like this" in the library. Michal Gajda [EMAIL PROTECTED]
Library conventions
After some discussions in the GHC developer mailing lists a small bunch of conventions around library design emerged. Currently things mainly concentrate on naming issues (everybody's delight :-), but it is only meant as a starting point: http://www.informatik.uni-muenchen.de/~Sven.Panne/hslibs-intro.html Please feel free to discuss, improve, and extend this proposal. If the feedback is quick enough, the conventions could already make their way into the upcoming final GHC 4.07 distribution, which would be a good thing. Although some parts might sound a little bit narrow-minded, keep in mind that we're not prescribing how to do things, but are collecting folklore and good habits. A sound collection of conventions improves readability of code, ease of use of a library, and last but not least makes the life of a library writer easier. Cheers, Sven