Haskell Cheatsheet

IO and Modules

Use this Haskell reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

IO Actions

main :: IO ()
main = do
  putStrLn "What is your name?"
  name <- getLine
  putStrLn ("Hello, " ++ name)
  print (length name)   -- print = putStrLn . show, works for any Show

IO a is an action that, when run by the runtime, can perform effects and produce an a.

Do Not Confuse <- and let

main = do
  line <- getLine       -- run IO action and bind result
  let upper = map toUpper line -- pure binding, no IO
  putStrLn upper

Use <- only inside do for monadic actions. Use let for pure values.

Command-Line Arguments and Exit

import System.Environment (getArgs, getProgName)
import System.Exit (exitFailure)

main :: IO ()
main = do
  args <- getArgs
  case args of
    [path] -> putStrLn ("reading " ++ path)
    _      -> putStrLn "usage: prog FILE" >> exitFailure

File IO (prefer Text)

-- String IO works but is slow for real workloads
main = do
  contents <- readFile "input.txt"
  putStrLn (take 100 contents)
-- Text IO is the production choice (text package)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO

main = do
  contents <- TIO.readFile "input.txt"
  TIO.writeFile "output.txt" (T.toUpper contents)

Also: appendFile, interact, and handle-based IO from System.IO (openFile, hGetLine, hClose).

Exceptions

File and network IO throws runtime exceptions. Handle them in IO with Control.Exception:

import Control.Exception

main :: IO ()
main = do
  result <- try (readFile "missing.txt") :: IO (Either IOException String)
  case result of
    Left e  -> putStrLn ("failed: " ++ show e)
    Right s -> putStr s
import Control.Exception
import System.IO

-- throwIO raises, catch handles, bracket guarantees cleanup
validate n = if n < 0 then throwIO (userError "negative") else pure n

main = bracket (openFile "data.txt" ReadMode) hClose $ \h -> do
  firstLine <- hGetLine h
  putStrLn firstLine

Use throwIO (not throw) inside IO, try/catch to recover, and bracket for acquire/use/release patterns (files, locks, connections). Pure code should still prefer Maybe/Either over exceptions.

Modules

module Geometry
  ( areaCircle
  , Point(..)
  ) where

areaCircle :: Double -> Double
areaCircle r = pi * r * r

data Point = Point Double Double

Import modules with import Data.List, selected names with import Data.Map (Map), and qualified modules with import qualified Data.Map as Map.

Common Imports

import Data.Char (toLower, toUpper, isDigit)
import Data.List (sort, sortOn, nub, group, intercalate, foldl')
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Control.Monad (when, unless, forM_, replicateM)
import Text.Read (readMaybe)

Prefer qualified imports for modules with common names like Data.Map and Data.Set. Map, Set, and Text live in the containers and text packages.

Data.Map Essentials

import qualified Data.Map.Strict as Map

m = Map.fromList [(1, "one"), (2, "two")]
OperationExample
lookupMap.lookup 1 m returns Maybe String
with defaultMap.findWithDefault "?" 9 m
insertMap.insert 3 "three" m
memberMap.member 2 m
deleteMap.delete 1 m
upsertMap.insertWith (+) word 1 counts
modifyMap.adjust (+1) key counts
mergeMap.unionWith (+) m1 m2
convertMap.toList m, Map.keys m, Map.elems m
sizeMap.size m

Use Data.Map.Strict for accumulators (word counts, tallies) so values do not pile up as thunks.

Data.Set Essentials

import qualified Data.Set as Set

s = Set.fromList [3, 1, 2, 1]      -- fromList [1,2,3]
Set.member 2 s                     -- True
Set.insert 4 s
Set.delete 1 s
Set.union s (Set.fromList [7, 8])
Set.intersection s (Set.fromList [2, 9])
Set.toList s                       -- ascending order
Set.size s