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:
| Module | Purpose |
|---|---|
Prelude | The conventional default imports |
Data.Char | Character operations (isDigit, toUpper) |
Data.List | List operations (sort, nub, intercalate) |
Data.Maybe | Maybe operations (fromMaybe, catMaybes) |
Data.Either | Either operations |
Data.Function | Function combinators (on, fix, &) |
Data.IORef | Mutable references in IO |
Data.Tuple | Tuple operations (fst, snd, swap) |
Data.Maybe, Data.Either | Helper functions |
Control.Monad | Monadic helpers (forM_, replicateM, when, unless) |
Control.Applicative | Applicative helpers |
Control.Exception | Exception handling |
System.IO | File handles |
System.Environment | Process environment |
System.Exit | Process exit |
System.IO.Error | IO error inspection |
Text.Read | readMaybe |
Text.Printf | printf |
Numeric | Numeric formatting |
Data.Bits | Bitwise operations |
Data.Foldable | The Foldable class and helpers |
Data.Traversable | The Traversable class |
Data.Functor | The 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:
| Package | Notes |
|---|---|
regex-tdfa | Pure Haskell, POSIX-extended; the conventional choice |
regex-pcre | PCRE-based, requires C library |
text-regex-tdfa | regex-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:
| Package | Format |
|---|---|
aeson | JSON; the conventional choice |
yaml | YAML |
xml-conduit | XML |
binary | Custom binary |
cereal | Custom 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:
| Package | Notes |
|---|---|
http-client | Low-level HTTP |
http-client-tls | TLS support |
req | High-level wrapper |
wreq | Lens-based HTTP client |
servant-client | Type-safe HTTP client |
For server-side:
| Package | Notes |
|---|---|
wai | The web application interface |
warp | The principal WAI-compatible web server |
servant-server | Type-safe API definition |
yesod | A full-stack web framework |
scotty | A 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.