
This is a ranty request for comments, and the more replies the better. 1. Namespace pollution The Prelude uses many simple and obvious names. Most programs don't use the whole Prelude, so names that aren't needed take up namespace with no benefit. 2. Monomorphism The Prelude defines many data types (e.g Lists), and operations on these types. Because the Prelude is imported automatically, programmers are encouraged to write their programs in terms of non-overloaded operators. These programs then fail to generalize. This is a highly non-academic concern. Many widely used libraries, such as Parsec, operate only on lists and not the newer and more efficient sequence types, such as bytestrings. 3. Supports obsolete programming styles The Prelude uses, and by means of type classes encourages, obsolete and naive programming styles. By providing short functions such as nub automatically while forcing imports to use sets, the Prelude insidiously motivates programmers to treat lists as if they were sets, maps, etc. This makes Haskell programs even slower than the inherent highlevelness of laziness requires; real programs use nub and pay dearly. More damagingly, the Prelude encourages programmers to use backtracking parsers. Moore's law can save you from nub, but it will never clarify "Prelude.read: no parse". 4. Stagnation Because every program uses the Prelude, every program depends on the Prelude. Nobody will willingly propose to alter it. (This is of course Bad; I hope Haskell' will take the fleeting opportunity to break to loop) 5. Inflexibility Because of Haskell's early binding, the Prelude always uses the implementation of modules that exists where the Prelude was compiled. You cannot replace modules with better ones. 6. Dependency Because every module imports the Prelude every module that the Prelude depends on, mutually depends with the Prelude. This creates huge dependency groups and general nightmares for library maintainers. 7. Monolithicity Every module the Prelude uses MUST be in base. Even if packages could be mutually recursive, it would be very difficult to upgrade any of the Prelude's codependents. 8. Monolithic itself Because the Prelude handles virtually everything, it is very large and cannot be upgraded or replaced piecemeal. Old and new prelude parts cannot coexist. 9. One-size-fits-all-ism Because the Prelude must satisfy everyone, it cannot be powerful, because doing so would harm error messages. Many desirable features of Haskell, such as overloaded map, have been abandoned because the Prelude needed to provide crutches for newbies. 10. Portability Because the Prelude must be available everywhere, it is forced to use only least-common-denominator features in its interface. Monad and Functor use constructor classes, even though MPTC/FD is usefully far more flexible. The Class_system_extension_proposal, while IMO extremely well designed and capable of alleviating most of our class hierarchy woes, cannot be adopted. 11. Committeeism Because the Prelude has such a wide audience, a strong committee effect exists on any change to it. This is the worst kind of committeeism, and impedes real progress while polluting the Prelude with little-used features such as fail in Monad (as opposed to MonadZero) and until. 12. There is no escape Any technical defect in Map could be fixed by someone writing a better Map; this has happened, and the result has been accepted. Defects in the PackedString library have been fixed, with the creation and adoption of ByteString. Defects in System.Time have been fixed, by the creation and adoption of Data.Time. Ditto for Binary and Arrays and Network and Regex. But this will never happen for the Prelude. A replacement Prelude cannot be adopted because it is so easy to take the implicit import of the default one. Nobody will go out of their way to 'import Prelude() ; import FixedPrelude'. Psychology trumps engineering. 13. There can be no escape The Prelude was designed by extremely smart people and was considered close to perfect at the time. It is almost universally hated now. Even if all the issues I describe could be fixed (which I consider unlikely), the Prelude will almost certainly be hated just as universally five years hence. 14. My future Given all these issues, I consider the only reasonable option is to discard the Prelude entirely. There will be no magic modules. Everything will be an ordinary library. HOFs like (.) are available from Control.Function. List ops come from Data.List. Any general abstractions can be added in abstract Sequence, Monad, etc. modules. Haskell will regain the kind of organic evolution whose lack currently causes Haskell to lose its lead over Python et al by the day. Stefan

Given all these issues, I consider the only reasonable option is to discard the Prelude entirely. There will be no magic modules. Everything will be an ordinary library. HOFs like (.) are available from Control.Function. List ops come from Data.List. Any general abstractions can be added in abstract Sequence, Monad, etc. modules. Haskell will regain the kind of organic evolution whose lack currently causes Haskell to lose its lead over Python et al by the day. I basically agree with a lot of the things you say. The only thing is: it's so convenient to have the Prelude. I can just start writing my haskell programs and don't have to worry about all kinds of imports. And you'll end up being repetitive: you'll import (.) and stuff like that in _every_ file. Yeah, this will definitely be more modular, but if we go for it, it's going to be so much more (tedious) work to create a new program.
-chris

On 3/24/07, Chris Eidhof
Given all these issues, I consider the only reasonable option is to discard the Prelude entirely. There will be no magic modules. Everything will be an ordinary library. HOFs like (.) are available from Control.Function. List ops come from Data.List. Any general abstractions can be added in abstract Sequence, Monad, etc. modules. Haskell will regain the kind of organic evolution whose lack currently causes Haskell to lose its lead over Python et al by the day. I basically agree with a lot of the things you say. The only thing is: it's so convenient to have the Prelude. I can just start writing my haskell programs and don't have to worry about all kinds of imports. And you'll end up being repetitive: you'll import (.) and stuff like that in _every_ file. Yeah, this will definitely be more modular, but if we go for it, it's going to be so much more (tedious) work to create a new program.
The solution is simple: * If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude. That should take of most issues. -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

On Mar 24, 2007, at 2:36 AM, Sebastian Sylvan wrote:
On 3/24/07, Chris Eidhof
wrote: Given all these issues, I consider the only reasonable option is to discard the Prelude entirely. There will be no magic modules. Everything will be an ordinary library. HOFs like (.) are available from Control.Function. List ops come from Data.List. Any general abstractions can be added in abstract Sequence, Monad, etc. modules. Haskell will regain the kind of organic evolution whose lack currently causes Haskell to lose its lead over Python et al by the day. I basically agree with a lot of the things you say. The only thing is: it's so convenient to have the Prelude. I can just start writing my haskell programs and don't have to worry about all kinds of imports. And you'll end up being repetitive: you'll import (.) and stuff like that in _every_ file. Yeah, this will definitely be more modular, but if we go for it, it's going to be so much more (tedious) work to create a new program.
The solution is simple:
* If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude. So if I'm writing a script, which has been working, then import Control.Monad, it all suddenly stops working?
I also think that you want to minimize the differences between an interpreted (interactive) version and a compiled version. It would be very weird for first-time users if their scripts work in ghci but break when they compile them. I'm sorry for being so negative. I like the idea, but I don't like it from a newbie-standpoint. The thing is: this is mostly handy for power-users, maybe we should do it for power-users only? We can still change the prelude to have no more code in there, but make it only a bunch of imports? -chris

Chris Eidhof writes:
On Mar 24, 2007, at 2:36 AM, Sebastian Sylvan wrote:
The solution is simple:
* If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude.
So if I'm writing a script, which has been working, then import Control.Monad, it all suddenly stops working?
No, that's an import declaration, not a module declaration.
So far, this is my favorite proposal, but I'm not sure it's better than
leaving things the way they are. There's a lot of useful stuff in the
Prelude, so the typical usage is likely to be "import Prelude hiding
(...)", which you can do right now.
On the other hand, making this like this explicit seems consistent with
Haskell's traditions.
--
David Menendez

On Saturday 24 March 2007 05:36, Sebastian Sylvan wrote:
On 3/24/07, Chris Eidhof
wrote: Given all these issues, I consider the only reasonable option is to discard the Prelude entirely. There will be no magic modules. Everything will be an ordinary library. HOFs like (.) are available from Control.Function. List ops come from Data.List. Any general abstractions can be added in abstract Sequence, Monad, etc. modules. Haskell will regain the kind of organic evolution whose lack currently causes Haskell to lose its lead over Python et al by the day.
I basically agree with a lot of the things you say. The only thing is: it's so convenient to have the Prelude. I can just start writing my haskell programs and don't have to worry about all kinds of imports. And you'll end up being repetitive: you'll import (.) and stuff like that in _every_ file. Yeah, this will definitely be more modular, but if we go for it, it's going to be so much more (tedious) work to create a new program.
The solution is simple:
* If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude.
That should take of most issues.
+1 for this opinion. The presence/absence of the "module" declaration seems like a very nice way to separate the student/newbie/just-writing-a-quick-hack class of use cases from the library-maintainer/large-scale-program-author class of use cases. Rob Dockins

On Sat, Mar 24, 2007 at 11:40:37AM -0400, Robert Dockins wrote:
On Saturday 24 March 2007 05:36, Sebastian Sylvan wrote:
The solution is simple:
* If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude.
That should take of most issues.
+1 for this opinion. The presence/absence of the "module" declaration seems like a very nice way to separate the student/newbie/just-writing-a-quick-hack class of use cases from the library-maintainer/large-scale-program-author class of use cases.
Thank you Sebastian, you just solved my #1 con. Stefan

Sebastian Sylvan wrote:
The solution is simple:
* If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude.
That should take of most issues.
I think this is ideal. I've always thought writing "import Prelude" was a good idea if one wants one's module to import the Prelude. It's one less corner case. -- Ashley Yakeley

I agree, I think this is what we need. Plus a decision of what names the builtin syntax refers to, like the type of 'a'. -- Lennart On Mar 26, 2007, at 23:30 , Ashley Yakeley wrote:
Sebastian Sylvan wrote:
The solution is simple: * If there is a "module M where" clause in the beginning of the file, then it's a "proper" module and shouldn't import the Prelude. * If there is no module declaration then it's a "quick'n dirty script" and should have the Prelude implicitly imported. * Interactive interpreters should probably import the Prelude. That should take of most issues.
I think this is ideal. I've always thought writing "import Prelude" was a good idea if one wants one's module to import the Prelude. It's one less corner case.
-- Ashley Yakeley
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Saturday 24 March 2007 03:48, Stefan O'Rear wrote:
1. Namespace pollution
The Prelude uses many simple and obvious names. Most programs don't use the whole Prelude, so names that aren't needed take up namespace with no benefit. [...]
Even though I think that the current Prelude is far from perfect, one should not forget that is a very solid foundation of a "common language": If one sees e.g. '(.)' or 'map', it is immediately clear to everybody what this means, without having to scan through (perhaps long) import lists. Of course one could hide some parts of the Prelude etc., but I think in the long run this only leads to confusion. Redefining common things, heavy use of tons of self-defined operators etc. all make maintenance much harder. Try reading Lisp code with heavy use of macros or C++ code with tons of overloadings. This is more like Sudoku solving than anything else, because there is no "common language" between the author and the reader anymore. And taking away the prelude is a little bit like taking away 'int', 'double', 'for', 'while' etc. from the C programmer...
11. Committeeism
Because the Prelude has such a wide audience, a strong committee effect exists on any change to it. This is the worst kind of committeeism, and impedes real progress while polluting the Prelude with little-used features such as fail in Monad (as opposed to MonadZero) and until.
Depending on your viewpoint, you can see this as a plus. Everybody agrees that finalizers are evil, but propose the removal of that method from java.lang.Object to the Java people. :-) My proposal would be to incrementally improve the Prelude, modularize it a bit more, fix the Num hierarchy, but basically leave it as it is. Cheers, S.

On 24/03/07, Stefan O'Rear
This is a ranty request for comments, and the more replies the better.
Without responding to any particular comment, my opinion is that we should have a minimal Prelude with functions like (.) that couldn't be reasonably redefined in any function. Most of the list functions should have to be imported, to encourage people to use a Map or Array and so on. Read should be in Text.Read to encourage people to use Parsec and so on. I wouldn't necessarily be against a minimal Prelude/expanded Prelude split determined by a 'module M where' declaration, as suggested by Sebastian. -- -David House, dmhouse@gmail.com

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 David House wrote:
On 24/03/07, Stefan O'Rear
wrote: This is a ranty request for comments, and the more replies the better.
Without responding to any particular comment, my opinion is that we should have a minimal Prelude with functions like (.) that couldn't be reasonably redefined in any function.
I can recall two variations on (.)... Strict composition, perhaps (.!), that is somehow strict in the functions that are its arguments. Unicode composition, i.e. use the Unicode character for function composition (?) instead of the overloaded (with module system syntax) "." symbol Not that these are worthy alternatives for our Prelude, just reasons that I don't entirely like the idea of any implicitly included prelude. Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGD57RHgcxvIWYTTURAjwuAKCeX5KJ+511lctcC5EXJ+7kYtsNqACfd/GS PSteOUuiJqYAaaJBwiblaso= =U/j/ -----END PGP SIGNATURE-----

why do people insist that what they don't need has no right to live? also, there doesn't seem to be anything left in the Prelude itself, it just re-exports everything from one particular collection of modules. so the Prelude isn't really a useful target for complaints anymore, only the implicit import Prelude and the organisation of the base package are. authors and readers of older haskell books, as well as other programmers caring about stability will want -package haskell98 to provide the one implicitly imported Prelude. for those about to rely on -package haskell-prime, things are still open, while those relying on -package base will want clear documentation on which versions of base are backwards-compatible with all those haskell programs currently out there relying on an implicit Prelude, and which are not.
1. Namespace pollution 2. Monomorphism 3. Supports obsolete programming styles
these points could be addressed by requiring explicit import Prelude, starting from packages haskell-prime and the next version of base.
4. Stagnation 5. Inflexibility 6. Dependency 7. Monolithicity
these points seem to apply to package base rather than just the Prelude.
8. Monolithic itself 9. One-size-fits-all-ism 10. Portability 11. Committeeism 12. There is no escape 13. There can be no escape
once most code-bases have shifted to explicit import Prelude, it will become easier
to replace that with import MyFavouritePrelude, where appropriate. that will also add
more force to the recommendation to be more specific about imports, eg, import
Data.List instead of import Prelude. once the Prelude is less attractive as an exaggerated
swiss army knife style dumping ground for and source of definitions, the focus will perhaps
shift to the separate modules it re-exports.
i could well imagine different projects and books defining their own Prelude, re-exporting
all those and only those modules needed or appropriate for their code. for instance, a
haskell programming tutorial will have different needs (only basics) than a graphics tutorial
(gui libs) than a book (functions provided in or disscussed in the book) than a script
(System.Environment, System.Directory,..) than a <insert your current project here>
(

I've submitted: http://hackage.haskell.org/trac/haskell-prime/ticket/124 which I hope covers the essence of the result of this thread. Thanks Ian

On 25/03/07, Ian Lynagh
I've submitted:
http://hackage.haskell.org/trac/haskell-prime/ticket/124
which I hope covers the essence of the result of this thread.
I'd hate to have to import things like Data.Function for such trivial functions as (.) and ($), which are so often used that they become almost like control structures and keywords in themselves. What did people think of my idea of a stripped down prelude containing primarily the functions like (.) and ($)? Here'd be my list: 1. Almost like control structures otherwise (.) flip ($) 2. To make including literals sane Char String Int Integer Num(..) 3. Other basic functions Eq(..) Ord((<), (>), (<=), (>=)) Show(show) 4. Miscellaneous id const undefined Of course, the precise details would be debateable. -- -David House, dmhouse@gmail.com

[reply-to set; dropping libraries] On Sun, Mar 25, 2007 at 04:33:51PM +0100, David House wrote:
On 25/03/07, Ian Lynagh
wrote: I've submitted:
http://hackage.haskell.org/trac/haskell-prime/ticket/124
which I hope covers the essence of the result of this thread.
I'd hate to have to import things like Data.Function for such trivial functions as (.) and ($)
You wouldn't have to import a number of different modules like Data.Function, you could just import Prelude. The only difference is that, for Real modules, you explicitly say that you want the Prelude, rather than sometimes needing magic like import Prelude () Thanks Ian

On 25/03/07, Ian Lynagh
You wouldn't have to import a number of different modules like Data.Function, you could just import Prelude.
I guess what I was getting at was that Haskell is very good at blurring the distinction between userland function and actual syntax. E.g. to the untrained eye 'otherwise' may seem like a keyword, but it's defined in Data.Bool. Functions like map and catamorphisms like maybe and foldr are used just like control structures, not to mention things like when and unless which are built to directly emulate control structures in other languages. As real control structures, like if and case, are always in scope, having _no_ functions imported by default would drive an unnatural wedge between function and control structure. -- -David House, dmhouse@gmail.com

On 3/25/07, David House
On 25/03/07, Ian Lynagh
wrote: I've submitted:
http://hackage.haskell.org/trac/haskell-prime/ticket/124
which I hope covers the essence of the result of this thread.
I'd hate to have to import things like Data.Function for such trivial functions as (.) and ($), which are so often used that they become almost like control structures and keywords in themselves. What did people think of my idea of a stripped down prelude containing primarily the functions like (.) and ($)? Here'd be my list:
1. Almost like control structures otherwise (.) flip ($)
2. To make including literals sane Char String Int Integer Num(..)
3. Other basic functions Eq(..) Ord((<), (>), (<=), (>=)) Show(show)
4. Miscellaneous id const undefined
Of course, the precise details would be debateable.
I think I like this proposal. Perhaps without 2 though (unless Num and String gets some attention). I'm not sure the "not automatically imported if proper module" rule is needed if the Prelude gets stripped down a bit, but I wouldn't mind it (it makes sense to make imports explicit in "proper" modules). So to summarize what I perceive to be the issues: * Do we want a new Prelude, or just hide the existing one? (I want a new, stripped down version) * Should this new Prelude be automatically included always, or should it be hidden in "proper modules" (I'm ambivalent). * Should there be a larger backwards compatible Prelude (I think Yes) * Shold this larger Prelude be implicitly imported for non-proper modules? (I think no, it should always be explicitly imported, perhaps through command line options) With regards to the first point, I think it's a misstake to just have "Large Prelude which is not implicitly imported" because everytime you need (.) or ($) people would probably just "import Prelude" and then you're stuck with the old problem again. So I do think stripping down the Prelude is essential. I think this is a separate issue that can be agreed upon regardless of the issue of wether it should be implicitly imported or not. -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

I support both reducing the prelude to just a few commonly used combinators, and requiring an explicit import Prelude. In response to a couple of Stefan's points: Stefan O'Rear wrote:
6. Dependency
Because every module imports the Prelude every module that the Prelude depends on, mutually depends with the Prelude. This creates huge dependency groups and general nightmares for library maintainers.
Not a problem in practice, for GHC at least: all modules below the Prelude use -fno-implicit-prelude, there's no recursive dependency. Also, if the Prelude were smaller, it would be much lower in the dependency tree which would make life easier.
7. Monolithicity
Every module the Prelude uses MUST be in base. Even if packages could be mutually recursive, it would be very difficult to upgrade any of the Prelude's codependents.
Not necessarily - the Prelude itself doesn't have to be in base. If we split up base, then Prelude would likely have to be in a separate package. Haskell' will need a separate Prelude, so the Haskell 98 Prelude will need to move to the haskell98 package. Cheers, Simon

On 28/03/07, Simon Marlow
I support both reducing the prelude to just a few commonly used combinators, and requiring an explicit import Prelude.
Just to clear things up: would you need to do an import Prelude to get at these few commonly used combinators, or would the import pull in the 'wider' Prelude, with a more expansive selection, more akin to the current Prelude? -- -David House, dmhouse@gmail.com

On 3/28/07, David House
On 28/03/07, Simon Marlow
wrote: I support both reducing the prelude to just a few commonly used combinators, and requiring an explicit import Prelude.
Just to clear things up: would you need to do an import Prelude to get at these few commonly used combinators, or would the import pull in the 'wider' Prelude, with a more expansive selection, more akin to the current Prelude?
I would vote for a Combinators module with the most important combinators, and a somewhat larger Prelude to support quick scripts and demonstrations. Jeffrey

On 28/03/07, Jeffrey Yasskin
I would vote for a Combinators module with the most important combinators, and a somewhat larger Prelude to support quick scripts and demonstrations.
I'd hate to have to import a module just to get at ($). Like I've mentioned before, some combinators are so ubiqutos they're almost like syntax. Seeing as the actual syntax will always be in scope, these common combinators would also have to be in scope all the time, which means placing them in the narrowed Prelude. -- -David House, dmhouse@gmail.com
participants (15)
-
Ashley Yakeley
-
Chris Eidhof
-
Claus Reinke
-
David House
-
David Menendez
-
dons@cse.unsw.edu.au
-
Ian Lynagh
-
Isaac Dupree
-
Jeffrey Yasskin
-
Lennart Augustsson
-
Robert Dockins
-
Sebastian Sylvan
-
Simon Marlow
-
Stefan O'Rear
-
Sven Panne