Since it sticks to concrete types in many cases (usually lists), it uses up the common namespace for function names (e.g., length), thereby requiring programmers to use qualified imports on a regular basis.

I think the first point stands on its own: there's a basic question we need to
ask ourselves about what we consider idiomatic Haskell code, and in my opinion,
partial functions is not a part of it. While that's an important point to
discuss, it's relatively straight-forward, so I won't be dwelling on it any
further.

The other three points rest around a central philosophy I have: programmers are
inherently lazy (in a good way), and will often choose the path of least
resistance. To demonstrate, consider the difference between using String and
Text for some simple concatenation:

(Without OverloadedStrings, this would be even longer.) It's not that the
second version is really that much worse than the first, it's just slightly
less convenient. And due to that extra bit of work, Text gets used less
often. You can see the same thing with Map versus associated lists, Vector
and lists, and so on.

Note: As Herbert pointed out to me, with GHC 7.4 and up, you could just use
the <> operator provided by Data.Monoid instance of `T.append`. So
consider the case where you need to use some Prelude functions that require a
String.

If you think that my assessment so far doesn't warrant any changes to our
tooling, turn back now, this blog post isn't for you. If you are interested
in some kind of a solution to this issue, I have two options for you.

basic-prelude

Points 1-3 above can actually be solved pretty easily: just create a new
prelude module that has better defaults. BasicPrelude, provided by the
basic-prelude package, does
just this. It exports more helper functions, avoids partial functions, and
exports a bunch of the common datatypes, like ByteString and HashMap.

Another important premise of BasicPrelude is that it doesn't replace any
existing types or type classes. It reuses the exact same Monad typeclass that
is exported by Prelude. That means that code using BasicPrelude is
completely compatible with "normal" Haskell code. Another way to put it is that
BasicPrelude is a non-revolutionary approach to improving the Haskell
programming experience.

basic-prelude is actually split up into two modules: BasicPrelude and
CorePrelude. BasicPrelude simply re-exports everything provided by
CorePrelude, and then adds in some missing components. CorePrelude is
intended to be a foundation for the creation of other preludes. It was
originally part of classy-prelude, but was then separated out by Dan Burton,
who now maintains basic-prelude with me. CorePrelude tries to export
components that would be usable by allPrelude replacements. For now, our
simple barometer of this is "would both BasicPrelude and ClassyPrelude use
this?"

BasicPrelude sticks to monomorphic functions for the most part, with a strong
bias towards lists (just like standard Prelude). It doesn't really do much
that's controversial, and should be a great approach to try out for people
experimenting with an alternate prelude. And if you don't like something about
it, you can either file an issue, or just create your own fork. Due to the
design of basic-prelude, forking does not create incompatible code, so it's
not a high-impact move.

classy-prelude

classy-prelude is the more radical prelude. As mentioned, it builds on top of
CorePrelude, just like BasicPrelude does. The distinction, however, is that
instead of providing monomorphic, list-biased functions, it creates a slew of
typeclasses and provides polymorphic functions. Unlike many common typeclasses,
these typeclasses are not intended to be used in a polymorphic context
themselves, but rather to avoid the need to use qualified imports to
disambiguate names. In other words, we're using typeclasses for namespacing
purposes only.

(Despite this, we actually have a fairly thorough test suite covering the
behavioral laws of these type classes. So you could theoretically write
polymorphic code with classy-prelude, it's just not what I originally
intended.)

This namespacing approach was fairly uncommon (perhaps classy-prelude was the
first usage of it?) when I first started classy-prelude, and as a result I
was unsure how well it would turn out in practice. At this point, I've been
using classy-prelude for a number of my projects (both personal and at
work), and the approach is certainly viable. I
personally greatly prefer it to the non-classy approach, and will almost
certainly be using it for the foreseeable future- likely until we get a better
namespacing solution in GHC itself.

There are of course some downsides, some of which can be worked around:

Error messages become more confusing. I have no good solution to that right
now. I don't think the messages are too daunting for experienced Haskellers,
but I would not recommend classy-prelude to beginners.

In some cases it is impossible for the compiler to figure out which type
you mean. For example, the following monomorphic code is completely
unambiguous:

The problem is that both singleton and lookup are polymorphic, and are not
used in the result, so there's no way to know which container to use.
Fortunately, there's an easy workaround: the as* functions. In our case, we
just replace the last line with:

people = asMap $ singleton "Michael" 28

Overall, the code is still shorter. As an added bonus, you can now simply
switch asMap to asHashMap to swap which container structure you use.

In some cases, keeping the same name can go beyond the capabilities of the
type system. For example, when working on classy-prelude-yesod,
overloading insert for both its usage in Persistent and containers like Map
proved to be a bit problematic, specifically when not using the return value.
For example, the following code doesn't compile:

_ <- runDB $ insert $ Person "Michael" 28

The options in this case are either to not use the overloaded name and
instead use a separately named function (in this case, insertDB), or to use a
disambiguating helper function (voidKey) that fixes the types- similar to the asMap
function described above. Those two solutions look like:

I'm not sure yet how I feel about these two approaches, but it definitely
stresses the point that we're using the typeclass system in an extreme manner.

classy-prelude-conduit and classy-prelude-yesod

These two packages build on top of classy-prelude to provide even more common
functionality. The former provides conduit and xml-conduit functions, while
the latter adds on top of that yesod, persistent, http-conduit, and a few
other things. classy-prelude-yesod has not been as thoroughly exercised as
the other packages discussed here, so you're more likely to run into issues
with it.

Conclusion

These alternate preludes are not for everyone, but I think they offer a lot to
certain audiences. If you want to try out a smaller move, I'd recommend
BasicPrelude. If you want to be a bit more experimental, go for
classy-prelude. If you decide to drop either one at any point, it should not
be overly onerous to switch back to normal, monomorphic, qualified imports.

I'm definitely interested to hear people's experience with these packages.
There are still lots of improvements to be made, more common functionality to
be added, and documentation to be written. Now's a great time to get involved!