Haskell 98 will by no means be the last revision of Haskell. On the contrary, we design it knowing that new language extensions (multi-parameter type classes, universal and existential quantification, pattern guards, etc, etc) are well on the way. However, Haskell 98 will have a special status: the intention is that Haskell compilers will continue to support Haskell 98 (given an appropriate flag) even after later versions of the language have been defined, and so the name `Haskell 98' will refer to a fixed, stable language.
This document exhaustively lists all the differences between Haskell 1.4 and Haskell 98. Only a very short summary is given here, together with references to the report text. All section numbers refer to the Haskell 98 language and library reports.
class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b fail :: String -> m a m1 >> m2 = m1 >>= \ _ -> m2 fail s = error s
class Monad m => MonadPlus m where mzero :: m a mplus :: m a -> m a -> m a
data Point = MkPoint { x,y :: Float } f1 :: Point -> Point f1 (MkPoint {x=xval, y=yval}) = MkPoint {x=xval+10, y=yval} f2 :: Point -> Point f2 (MkPoint {x, y}) = MkPoint {x=x+10, y}In f2 the names of the values held in the fields 'punned' with the field labels themselves, both in the pattern match (which binds x,y and in the record construction on the right hand side. This feature is the one that has been removed.
fpat -> qvar = patwhere we have qvar rather than var. Reason: the field name might only be in scope in qualified form.
funlhs -> ( funlhs ) {apat}This permits definitions like:
(a &&& b) x = a x && b x
module M where { import A; ; import B; f x = x }
data Nat = Zero | Succ NatFurthermore, the current implementation doesn't even work for Integer.
map :: (a -> b) -> [a] -> [b] filter :: (a -> Bool) -> [a] -> [a] (++) :: [a] -> [a] -> [a] concat :: [[a]] -> [a]Rename the operation of class Functor as fmap
class Functor f where fmap :: (a -> b) -> f a -> f b -- was map
class (Real a, Enum a) => Integral a where quot, rem :: a -> a -> a div, mod :: a -> a -> a quotRem, divMod :: a -> a -> (a,a) toInteger :: a -> Integer -- Minimal complete definition: -- quotRem, toInteger n `quot` d = ... n `rem` d = ... n `div` d = ... n `mod` d = ... divMod n d = ...
filterM :: (a -> m Bool) -> [a] -> m [a] -- didn't exist before msum :: MonadPlus m => [m a] -> m a -- was concat guard :: MonadPlus m => Bool -> m ()Notice that guard remains in MonadPlus and uses mzero not fail. The latter is reserved exclusively for pattern-match failure.
(=<<) :: Monad m => (a -> m b) -> m a -> m b f =<< x = x >>= f
x / y = x * recip y
negate x = 0 - x
unionBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] unionBy eq xs ys = xs ++ foldl (flip (deleteBy eq)) (nubBy eq ys) xs
realToFrac :: (Real a, Fractional b) => a -> b realToFrac = fromRational . toRational
span p [] = ([],[]) span p xs@(x:xs') | p x = (x:ys,zs) | otherwise = ([],xs) where (ys,zs) = span p xs'
enumFromThen c c' = map toEnum [fromEnum c, fromEnum c' .. fromEnum lastChar] where lastChar :: Char lastChar | c' < c = minBound | otherwise = maxBound
numericEnumFromTo n m = takeWhile (<= m+1/2) (numericEnumFrom n) numericEnumFromThenTo n n' m = takeWhile p (numericEnumFromThen n n') where p | n' > n = (<= m + (n'-n)/2) | otherwise = (>= m + (n'-n)/2)The extra 1/2 gives better behaviour at the edges of the range.
readsPrec p = readParen False (\r -> [(c,t) | ('\'':s,t)<- lex r, (c,"\'") <- readLitChar s])
cycle :: [a] -> [a] cycle [] = error "Prelude.cycle: empty list" cycle xs = xs' where xs' = xs ++ xs'
show :: a -> String showsPrec _ x s = show x ++ s show x = showsPrec 0 x ""
showList [] = showString "[]" showList (x:xs) = showChar '[' . shows x . showl xs where showl [] = showChar ']' showl (x:xs) = showChar ',' . shows x . showl xs
isSym c = c `elem` "!@#$%&*+./<=>?\\^|:-~"(The Haskell 1.4 version treated space as a symbol character.)
match :: (Eq a) => [a] -> [a] -> ([a],[a]) match (x:xs) (y:ys) | x == y = match xs ys match xs ys = (xs,ys)
genericTake 0 _ = []
unfoldr :: (b -> Maybe (a,b)) -> b -> [a] unfoldr f b = case (f b) of Nothing -> [] Just (a,b) -> a : unfoldr f b
insert :: Ord a => a -> [a] -> [a]This is consistent with the other `By' functions, which all have a non-By version.
-- transpose is lazy in both rows and columns, -- and works for non-rectangular 'matrices' -- For example, transpose [[1,2],[3,4,5],[]] = [[1,3],[2,4],[5]] transpose :: [[a]] -> [[a]] transpose [] = [] transpose ([] : xss) = transpose xss transpose ((x:xs) : xss) = (x : [h | (h:t) <- xss]) : : transpose (xs : [t | (h:t) <- xss])
isPrefixOf :: (Eq a) => [a] -> [a] -> Bool isPrefixOf [] _ = True isPrefixOf _ [] = False isPrefixOf (x:xs) (y:ys) = x == y && isPrefixOf xs ys
phase :: RealFloat a => Complex a -> a phase (0 :+ 0) = 0 phase (x :+ y) = atan2 y x
exitFailure :: IO a