Punt the Prelude

by Edward Z. Yang

Conservation attention notice. What definitions from the Haskell 98 Prelude tend to get hidden? I informally take a go over the Prelude and mention some candidates.

(.) in the Prelude is function composition, that is, (b -> c) -> (a -> b) -> a -> c. But the denizens of #haskell know it can be much more than that: the function a -> b is really just the functor, so a more general type is Functor f => (b -> c) -> f b -> f c, i.e. fmap. Even more generally, (.) can indicate morphism composition, as it does in Control.Category.

all, and, any, concat, concatMap, elem, foldl, foldl1, foldr, foldr1, mapM_, maximum, minimum, or, product, sequence_. These are all functions that operate on lists, that easily generalize to the Foldable type class; just replace [a] with Foldable t => t a. They can be found in Data.Foldable.

mapM, sequence. These functions generalize to the Traversable type class. They can be found in Data.Traversable.

Any numeric function or type class. Thurston, Thielemann and Johansson wrote numeric-prelude, which dramatically reorganized the hierarchy of numeric classes and generally moved things much closer to their mathematical roots. While dubbed experimental, it's seen airplay in more mathematics oriented Haskell modules such as Yorgey's species package.

Any list function. Many data structures look and smell like lists, and support some set of the operations analogous to those on lists. Most modules rely on naming convention, and as a result, list-like constructs like vectors, streams, bytestrings and others ask you to import themselves qualified. However, there is Data.ListLike which attempts to encode similarities between these. Prelude.Listless offers a version of the Prelude minus list functions.

Monad, Functor. It is widely believed that Monad should probably be an instance of Applicative (and the category theorists might also have you insert Pointed functors in the hierarchy too.) The Other Prelude contains this other organization, although it is cumbersome to use in practice since the new class means most existing monad libraries are not usable.

repeat, until. There is an admittedly oddball generalization for these two functions in Control.Monad.HT. In particular, repeat generalizes the identity monad (explicit (un)wrapping necessary), and until generalizes the (->) a monad.

map. It's fmap for lists.

zip, zipWith, zipWith3, unzip. Conal's Data.Zip generalize zipping into the Zip type class.

IO. By far you'll see the most variation here, with a multitude of modules working on many different levels to give extra functionality. (Unfortunately, they're not really composable...)

  • System.IO.Encoding makes the IO functions encoding aware, and uses implicit parameters to allow for a "default encoding." Relatedly, System.UTF8IO exports functions just for UTF-8.
  • System.IO.Jail lets you force input-output to only take place on whitelisted directories and/or handles.
  • System.IO.Strict gives strict versions of IO functions, so you don't have to worry about running out of file handles.
  • System.Path.IO, while not quite IO per se, provides typesafe filename manipulation and IO functions to use those types accordingly.
  • System.IO.SaferFileHandles allows handles to be used with monadic regions, and parametrizes handles on the IO mode they were opened with. System.IO.ExplicitIOModes just handles IOMode.