Changes to the Haskell 1.3 Prelude

The following changes are being made in the Prelude for Haskell 1.3. The report contains the complete Prelude. I have altered the formatting of the Prelude somewhat. PreludeBuiltin has been removed since we no longer have interface files and it was pretty much vacuous. Also, instance declarations that merely bind every method onto a primitive have been abbreviated. Many comments have been removed - functions like `head' are self-documenting. I have also moved comments between the signature and the definition of an object. All types now have a data declaration, even when such a declaration is not syntacticly valid.

New Types

The following types are now in the Prelude:
data  Maybe a  =  Nothing | Just a	deriving (Eq, Ord, Read, Show)

data  Either a b  =  Left a | Right b	deriving (Eq, Ord, Read, Show)

data  Void  -- No constructor, not in any classes

Changes to Ord

In Haskell 1.2, two comparisons are required to do a "three way branch":
    if x == y then ...
    else if x < y then ...
    else ...
Even a standard two way branch can be inefficient - here's the default definition of "<" in the standard prelude:
x < y = x <= y && x /= y
Instead of defining a <= operator which returns just two values, it is almost as easy to define an operator which returns three different values:
   case compare x y of
    EQ -> ...
    LT -> ...
    GT -> ...
The constructors EQ , LT ,and GT belong to a new type: Ordering. In addition to this efficiency problem, many uses of Ord such as sorting or operations on ordered binary trees assume total ordering. The compare operation formalizes this concept: it can not return a value which indicates that its arguments are unordered. Programmers are free to define a class for partial orderings; here, we simply state that Ord is reserved for total orderings.


Add toEnum and fromEnum to Enum

Haskell 1.2 provides very limited facilities for operating on enumerations. The following elementary operations must be implemented in an obscure and inefficient manner, if at all:



Strictness annotations in Ratio and Complex

Augustsson's FPCA'94 paper demonstrates very significantly lower memory requirements when these annotations are added to Complex. Adding similar annotations to Ratio should have a similar effect.

Whereas changing the strictness of lists or integers would break many programs, only the most contrived programs will be affected by this change.


Using Int in list operations

The Haskell 1.2 prelude forces the use of Integer rather than the more efficient Int for the very common operations take, drop, !!, and splitAt. There are only two circumstances where the overhead of using Integer's is worthwhile: Users of these very large datasets are probably already using implementations where maxInt == 2^31-1 or maxInt == 2^63-1 where the problem is less likely to occur. The old definitions can be placed in a library should problems arise.


New functions: replicate, lookup, curry, uncurry.

The following functions are deemed sufficiently useful that they should be added to the Haskell Prelude.



Moving functions to libraries

A large prelude helps the programmer by providing a wide range of pre-written functions to use and combine. It also hinders the programmer by making the language larger to learn, preventing the programmer from using prelude names for their own purposes and slowing down compilation.

It is possible to have our cake and eat it by simply moving rarely used functions into standard libraries (the language size remains the same but the "core language" gets smaller).

The following changes are based on counting how many times certain functions are used in a large body of Haskell programs (i.e. the Glasgow Haskell repository).

Many functions have been moved: see the new prelude to find out what remains.

The Bounded class

Add the class
class Bounded a where
  minBound, maxBound :: a
This class provides a convenient name for the minimum and maximum values in a type. Instances for Int and Char replace maxInt, minInt, maxChar, minChar. No instance will be defined for floats since it's not obvious whether to use infinity or the greatest finite value. Bounded is intended for carrying the range in enumerated classes or for verifying maps from Integers onto a type. The bounded class will be derivable for enumerations and tuples only. Note these class methods take no argument: you use minBound :: Char instead of minBound 'x'. This is inconsistant with the treatment of class-wide parameters (for example, floatRadix) elsewhere but seems to be a cleaner design.

Numeric Issues

Haskell 1.2 provides no way to detect IEEE arithmetic values such as "NaN" or "Infinity". This seemed reasonable since Haskell 1.2 (and 1.3) doesn't require IEEE arithmetic.

Providing everything numerical analysts could ask for requires a large amount of work, especially since the basic operations do not fit into the existing numeric classes (Num, Ord, ...). We are planning to create a library which will provide strict LIA conformance. However, a few simple additions to the numerics will make it possible to take advantage of some features of IEEE floating point operations.



Simplified Lex

The lex function is very inefficient and overly complex. Some of this complexity is necessary to ensure that almost any value that is printed out using standard Read and Show instances can be read back in. (Exceptions: functions and infinite data structures.) However, lex is able to parse several tokens that are never produced by these Read, Show instances.




Add undefined to the prelude. Previous proposals used _ or _|_ as the name.
undefined = error "undefined{Prelude}"
It is expected that compilers will recognize this and insert error messages which are more appropriate to the context in which undefined appears.

The Monad class

The Haskell 1.3 IO proposal uses the symbols ">>", ">>=" and "return" for the IO monad operations and a separate proposal provides syntactic sugar to make monadic code even easier to write. The provision of constructor classes makes it possible to define these symbols as methods in a "monad class" allowing the symbols and sugar to be used for any monad.

Changes: Add these classes to Prelude:

  infixr 1  >>, >>=

  class Functor where
    map :: (a -> b) -> m a -> m b

  class Monad m where
    (>>=) :: m a -> (a -> m b) -> m b
    (>>)  :: m a -> m b -> m b
    return :: a -> m a

  class Monad m => MonadZero m where
    zero :: m a

  class MonadZero m => MonadPlus m where
    (++) :: m a -> m a -> m a

with Monad instances for [], Maybe, and IO; MonadZero and MonadPlus instances for [] and Maybe.

Minor Changes

Back to the Haskell Report.