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")]
| Operation | Example |
|---|---|
| lookup | Map.lookup 1 m returns Maybe String |
| with default | Map.findWithDefault "?" 9 m |
| insert | Map.insert 3 "three" m |
| member | Map.member 2 m |
| delete | Map.delete 1 m |
| upsert | Map.insertWith (+) word 1 counts |
| modify | Map.adjust (+1) key counts |
| merge | Map.unionWith (+) m1 m2 |
| convert | Map.toList m, Map.keys m, Map.elems m |
| size | Map.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