Polyglot
Languages Haskell stdlib
Haskell § stdlib

Prelude and base

The Haskell standard library is partitioned into the Prelude — implicitly imported into every module — and the broader base package, plus several adjacent packages (containers, text, bytestring, array, deepseq) that are conventionally bundled with GHC. The base package is small by the standards of mainstream languages; the Haskell ecosystem provides much of what might be considered “standard” through other packages on Hackage. Familiarity with the Prelude and with the principal Data.* modules is part of fluency in the language; the broader ecosystem (covered briefly at the end) is the source for cryptography, networking, JSON, regular expressions, and the rest.

This page surveys the principal modules. The full standard library is too large to document exhaustively; the pages on individual topics (Data structures, Strings, IO, etc.) cover their domains in depth.

The Prelude

The Prelude is implicitly imported into every Haskell file:

-- Available without explicit import:

-- Types:
data Maybe a, Either a b, IO a, [a], Bool, Char, Int, Integer, Float, Double, ...

-- Type classes:
Eq, Ord, Show, Read, Enum, Bounded, Num, Fractional, Floating, Integral, Real, ...
Functor, Applicative, Monad, Foldable, Traversable, ...

-- Functions:
id, const, flip, ($), (.), curry, uncurry
map, filter, foldr, foldl, foldr1, foldl1
length, null, head, tail, init, last, reverse, take, drop, splitAt
zip, zipWith, unzip, lookup, elem, notElem
sum, product, maximum, minimum
print, putStr, putStrLn, getLine, getChar, getContents, interact
readFile, writeFile, appendFile

-- Operators:
(+), (-), (*), (/), (^), (^^), (**), div, mod, quot, rem
(==), (/=), (<), (>), (<=), (>=), compare
(&&), (||), not, otherwise
(++), (:), (!!)

The Prelude carries the foundational vocabulary. To suppress it:

import Prelude ()
import qualified Prelude as P

Or, with the NoImplicitPrelude language extension:

{-# LANGUAGE NoImplicitPrelude #-}
import RIO       -- a custom prelude

Several alternative preludes (relude, rio, protolude, classy-prelude) provide curated replacements that exclude partial functions and prefer Text over String. They are worth considering for new projects.

base package

The base package is shipped with GHC and provides:

ModulePurpose
PreludeThe conventional default imports
Data.CharCharacter operations (isDigit, toUpper)
Data.ListList operations (sort, nub, intercalate)
Data.MaybeMaybe operations (fromMaybe, catMaybes)
Data.EitherEither operations
Data.FunctionFunction combinators (on, fix, &)
Data.IORefMutable references in IO
Data.TupleTuple operations (fst, snd, swap)
Data.Maybe, Data.EitherHelper functions
Control.MonadMonadic helpers (forM_, replicateM, when, unless)
Control.ApplicativeApplicative helpers
Control.ExceptionException handling
System.IOFile handles
System.EnvironmentProcess environment
System.ExitProcess exit
System.IO.ErrorIO error inspection
Text.ReadreadMaybe
Text.Printfprintf
NumericNumeric formatting
Data.BitsBitwise operations
Data.FoldableThe Foldable class and helpers
Data.TraversableThe Traversable class
Data.FunctorThe Functor class and helpers

Data.List

The list module:

import Data.List

sort :: Ord a => [a] -> [a]
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortOn :: Ord b => (a -> b) -> [a] -> [a]
group :: Eq a => [a] -> [[a]]
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
nub :: Eq a => [a] -> [a]
delete :: Eq a => a -> [a] -> [a]
intersperse :: a -> [a] -> [a]
intercalate :: [a] -> [[a]] -> [a]
foldl' :: (b -> a -> b) -> b -> [a] -> b      -- strict left fold
isPrefixOf, isSuffixOf, isInfixOf :: Eq a => [a] -> [a] -> Bool
partition :: (a -> Bool) -> [a] -> ([a], [a])
find :: (a -> Bool) -> [a] -> Maybe a
findIndex :: (a -> Bool) -> [a] -> Maybe Int
inits, tails :: [a] -> [[a]]
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

The conventional uses:

sortBy (compare `on` fst) [(2, 'a'), (1, 'b'), (3, 'c')]
-- [(1,'b'), (2,'a'), (3,'c')]

intercalate ", " ["a", "b", "c"]
-- "a, b, c"

partition (> 0) [-1, 2, -3, 4]
-- ([2, 4], [-1, -3])

Data.Map.Strict and Data.Set

The containers package provides balanced-tree-based maps and sets:

import qualified Data.Map.Strict as Map
import qualified Data.Set as Set

m :: Map.Map String Int
m = Map.fromList [("alice", 30), ("bob", 28)]

age :: Maybe Int
age = Map.lookup "alice" m

s :: Set.Set Int
s = Set.fromList [1, 2, 3, 4, 5]

-- Conventional pattern:
-- import qualified Data.Map.Strict as M
-- import Data.Map.Strict (Map)
-- M.lookup, M.insert, etc.

The full treatment is in Data structures.

For unordered (hash-based) variants, Data.HashMap.Strict from unordered-containers offers O(log n) operations through hashing.

Data.Text and Data.ByteString

The conventional contemporary text and binary handling:

import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import qualified Data.ByteString as BS
import Data.Text.Encoding (decodeUtf8, encodeUtf8)

text :: T.Text
text = T.pack "hello, 世界"

-- Round-trip through bytes:
bytes :: BS.ByteString
bytes = encodeUtf8 text

back :: T.Text
back = decodeUtf8 bytes

-- File I/O:
contents <- TIO.readFile "input.txt"
TIO.writeFile "output.txt" contents

The full treatment is in Strings.

Control.Monad and Control.Applicative

The principal monadic helpers:

import Control.Monad

when :: Applicative f => Bool -> f () -> f ()
unless :: Applicative f => Bool -> f () -> f ()
guard :: Alternative f => Bool -> f ()
forever :: Applicative f => f a -> f b
replicateM :: Applicative m => Int -> m a -> m [a]
replicateM_ :: Applicative m => Int -> m a -> m ()
forM, forM_ :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
mapM, mapM_ :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
sequence, sequence_ :: (Traversable t, Monad m) => t (m a) -> m (t a)
filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a]
foldM, foldM_ :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
join :: Monad m => m (m a) -> m a
void :: Functor f => f a -> f ()
liftM, liftM2 :: Monad m => ...

The conventional uses:

when (n > 0) $ do
    putStrLn "positive"
    process n

forM_ [1..10] $ \i -> do
    putStrLn ("Step " ++ show i)
    process i

replicateM 5 (randomRIO (0, 100))     -- 5 random numbers

Control.Exception

Exception handling:

import Control.Exception

throwIO :: Exception e => e -> IO a
catch :: Exception e => IO a -> (e -> IO a) -> IO a
try :: Exception e => IO a -> IO (Either e a)
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
finally :: IO a -> IO b -> IO a
mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b

The full treatment is in Error handling.

System.IO and System.Environment

The principal I/O modules:

import System.IO
import System.Environment

stdin, stdout, stderr :: Handle
openFile :: FilePath -> IOMode -> IO Handle
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
hGetLine :: Handle -> IO String
hPutStr :: Handle -> String -> IO ()
hPutStrLn :: Handle -> String -> IO ()
hClose :: Handle -> IO ()

getArgs :: IO [String]
getProgName :: IO String
lookupEnv :: String -> IO (Maybe String)
getEnv :: String -> IO String
setEnv :: String -> String -> IO ()

The full treatment of I/O is in IO.

Numeric and Data.Bits

Numeric provides parse/show for various numeric formats:

import Numeric

showHex :: Integer -> ShowS
showOct :: Integer -> ShowS
showFFloat :: RealFloat a => Maybe Int -> a -> ShowS
showEFloat :: RealFloat a => Maybe Int -> a -> ShowS
readHex, readOct, readDec :: ReadS Int

Data.Bits provides bitwise operations:

import Data.Bits

(.&.), (.|.), xor :: Bits a => a -> a -> a
shiftL, shiftR :: Bits a => a -> Int -> a
testBit :: Bits a => a -> Int -> Bool
setBit, clearBit :: Bits a => a -> Int -> a
popCount :: Bits a => a -> Int

Data.Function

Function combinators:

import Data.Function

id :: a -> a
const :: a -> b -> a
flip :: (a -> b -> c) -> b -> a -> c
(.) :: (b -> c) -> (a -> b) -> a -> c
($) :: (a -> b) -> a -> b
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
(&) :: a -> (a -> b) -> b      -- reverse application
fix :: (a -> a) -> a            -- fixed-point combinator

The on combinator is especially useful:

sortBy (compare `on` length) ["abc", "a", "ab"]
-- ["a", "ab", "abc"]

Data.Foldable and Data.Traversable

The classes that admit operations across container types:

import Data.Foldable

length, null, elem, sum, product, minimum, maximum
toList :: Foldable t => t a -> [a]
foldr, foldl, foldl', foldMap

import Data.Traversable

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
mapM, sequence

Treated in Functors and applicatives.

Text.Read and Text.Printf

Text.Read.readMaybe is the conventional safe parser:

import Text.Read (readMaybe)

parseInt :: String -> Maybe Int
parseInt = readMaybe

parseDouble :: String -> Maybe Double
parseDouble = readMaybe

Text.Printf provides C-style formatting:

import Text.Printf

main = do
    printf "Hello, %s, age %d\n" "Alice" (30 :: Int)
    printf "Pi: %.4f\n" (3.14159 :: Double)
    let s = printf "value: %d" (42 :: Int) :: String
    putStrLn s

Time and dates

The conventional time handling is through the time package:

import Data.Time

getCurrentTime :: IO UTCTime
getCurrentTimeZone :: IO TimeZone
diffUTCTime :: UTCTime -> UTCTime -> NominalDiffTime
addUTCTime :: NominalDiffTime -> UTCTime -> UTCTime

formatTime :: TimeLocale -> String -> t -> String
parseTimeM :: (MonadFail m) => Bool -> TimeLocale -> String -> String -> m t

The conventional pattern:

import Data.Time

main = do
    now <- getCurrentTime
    let formatted = formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S" now
    putStrLn formatted

The time package is part of the GHC bootstrap libraries and is available without separate installation.

Random numbers

The conventional random-number generator is in the random package:

import System.Random

randomRIO :: (Random a) => (a, a) -> IO a
randomR :: (Random a, RandomGen g) => (a, a) -> g -> (a, g)
random :: (Random a, RandomGen g) => g -> (a, g)
randoms :: (Random a, RandomGen g) => g -> [a]

main = do
    n <- randomRIO (1, 100)         -- IO Int
    print n

For cryptographic randomness, crypto-rng or cryptonite’s Crypto.Random:

import Crypto.Random

main = do
    drg <- getSystemDRG
    let (bytes, drg') = randomBytesGenerate 16 drg :: (ByteString, SystemDRG)
    print bytes

Regular expressions

Haskell does not have a regex syntax in the language; the conventional regex packages are:

PackageNotes
regex-tdfaPure Haskell, POSIX-extended; the conventional choice
regex-pcrePCRE-based, requires C library
text-regex-tdfaregex-tdfa adapted for Text
import Text.Regex.TDFA

let matches = "hello" =~ "[a-z]+" :: Bool       -- True
let result = "hello" =~ "([a-z]+)" :: [[String]]

The interface is unconventional; many programmers reach for parser combinator libraries (parsec, megaparsec, attoparsec) instead.

JSON, XML, and other serialisation

The standard library does not include JSON or XML; the conventional packages are:

PackageFormat
aesonJSON; the conventional choice
yamlYAML
xml-conduitXML
binaryCustom binary
cerealCustom binary

The aeson interface uses type classes:

import Data.Aeson

data Person = Person { name :: String, age :: Int }
    deriving (Generic, Show, ToJSON, FromJSON)

main = do
    let alice = Person { name = "Alice", age = 30 }
    let bytes = encode alice
    case eitherDecode bytes of
        Right p -> print (p :: Person)
        Left  e -> putStrLn e

HTTP and networking

The conventional packages for HTTP:

PackageNotes
http-clientLow-level HTTP
http-client-tlsTLS support
reqHigh-level wrapper
wreqLens-based HTTP client
servant-clientType-safe HTTP client

For server-side:

PackageNotes
waiThe web application interface
warpThe principal WAI-compatible web server
servant-serverType-safe API definition
yesodA full-stack web framework
scottyA lightweight Sinatra-style framework

Cryptography

The conventional package is cryptonite:

import Crypto.Hash

let hash = hashWith SHA256 (BS.pack "hello") :: Digest SHA256
print hash

For higher-level cryptography (TLS, authenticated encryption), the cryptonite and tls packages provide the foundation; libraries like wai-extra, cookie, and jose build on top.

A note on the broader ecosystem

The Haskell ecosystem extends well beyond base:

  • Database: persistent, esqueleto, postgresql-simple, mysql-simple.
  • Web: yesod, servant, scotty, spock, iohk.
  • Concurrency: async, stm, parallel, pipes, conduit, streamly.
  • Testing: hspec, tasty, quickcheck, hedgehog, tasty-quickcheck.
  • Logging: katip, monad-logger, co-log.
  • Error handling: exceptions, safe-exceptions, validation.
  • Effects: mtl, polysemy, effectful, freer-simple, cleff.
  • GUI: gtk4, wxHaskell, monomer, obelisk.
  • Compilers: bnfc, parsec, megaparsec, attoparsec, happy, alex.

For most application code, the conventional approach is to start with the standard library and the containers, text, and bytestring packages, and reach for additional libraries as needed. The Stackage LTS snapshots curate compatible package versions; the conventional contemporary advice is to use the LTS resolver for production code.

The discipline of choosing among libraries is part of fluency in Haskell. The conventions are well-established but the trade-offs between alternatives — parsec vs megaparsec, aeson vs aeson-pretty vs data-default, mtl vs polysemy — vary by project requirements. Hackage and Hoogle are the conventional discovery tools; the broader Haskell community on Reddit, Discord, and elsewhere admits substantial discussion of the trade-offs.