Haskell essentials: 50 cards on types, type classes, laziness and monads
Haskell fundamentals with short code: types and type classes, pattern matching, laziness, Maybe and Either, folds, Functor, Applicative and Monad.
Practice now
Study without an account
add :: Int -> Int -> Int?Scheduled with the default Askesis timings. Progress is saved in this browser.
All 50 cards
- 1How do you read
add :: Int -> Int -> Int?addtakes anIntand returns a function of typeInt -> Int:->associates to the right, so the type meansInt -> (Int -> Int)This is currying:add 2 3means(add 2) 3, andadd 2on its own is a function of typeInt -> Int. - 2Operator sectionsAn operator with one side filled in, giving a function:
(+ 1)adds one,(2 ^)raises 2 to a power,(/ 2)halves(- 1)is the number negative one, not a section; writesubtract 1instead. - 3What does
Eq a =>mean inlookup :: Eq a => a -> [(a, b)] -> Maybe b?A class constraint:acan be any type with anEqinstance, so keys can be compared with== - 4
typevsnewtypevsdatatypegives an existing type another name;newtypemakes a distinct type around exactly one field, with no runtime cost;datadefines a new algebraic data type with any number of constructors and fields - 5Define a sum type for shapes and an area functionhaskell
data Shape = Circle Double | Rect Double Double area :: Shape -> Double area (Circle r) = pi * r * r area (Rect w h) = w * h - 6What does record syntax give you?Named fields with an accessor function for each, and update syntax that copies a value with some fields changedhaskell
data User = User { name :: String, age :: Int } birthday :: User -> User birthday u = u { age = age u + 1 } - 7Get
show,==and ordering for a type without writing instanceshaskelldata Suit = Hearts | Spades deriving (Show, Eq, Ord)DerivedOrdorders constructors in the order they are declared, soHearts < Spades. - 8Write a
Showinstance by handhaskelldata Color = Red | Green instance Show Color where show Red = "red" show Green = "green" - 9Declare a type class with a default methodhaskell
class Describable a where describe :: a -> String describe _ = "a thing"An instance can overridedescribeor keep the default with an empty body:instance Describable Bool. - 10
IntvsIntegerIntis a fixed-size machine integer (64 bits with GHC on 64-bit platforms) that silently overflows;Integerhas arbitrary precision - 11What is
Stringin Haskell?A type synonym for[Char]: a linked list of charactersFor serious text processing,Textfrom thetextpackage is far more efficient. - 12What is the kind of
Maybe?* -> *(also writtenType -> Type): it takes a type such asIntto make a concrete typeThat’s whyMaybeand[]can haveFunctorinstances butIntcan’t. Check kinds in GHCi with:k. - 13Sum a list with pattern matchinghaskell
total :: [Int] -> Int total [] = 0 total (x:xs) = x + total xs - 14What happens when no pattern matches?A runtime exception (non-exhaustive patterns); compile with
-Wallto get a warning about missing cases - 15What does
xs@(x:_)bind?xsto the whole list andxto its first element:@makes an as-pattern, and_ignores the rest - 16GuardsConditions tried from top to bottom, each with its own result;
otherwiseis simplyTruehaskellsign :: Int -> String sign n | n < 0 = "negative" | n == 0 = "zero" | otherwise = "positive" - 17
wherevslet … inwhereattaches bindings to a whole definition, visible in all its guards;let … inis an expression that can appear anywhere - 18Match on a value in the middle of an expressionhaskell
describe xs = case xs of [] -> "empty" [_] -> "one" _ -> "many" - 19What does
x = x + 1mean in Haskell?A recursive definition ofxin terms of itself, which loops forever when evaluated; Haskell has no reassignment - 20What does
take 3 (cycle [1, 2])return?[1,2,1]:cyclebuilds an infinite list, and laziness computes only the elements that are needed - 21What is a thunk?A suspended computation: an unevaluated expression stored until its value is needed
- 22Weak head normal form (WHNF)Evaluated only as far as the outermost constructor or lambda;
Just (1 + 1)and(undefined, 2)are both in WHNF - 23What does
fst (1, undefined)return?1: the second component is never evaluated, soundefinednever throws - 24What does
seq a bdo?Evaluatesato weak head normal form, then returnsbf $! xusesseqto forcexbefore applyingf. - 25Why prefer
foldl'tofoldlfor summing a long list?foldlis lazy in its accumulator and can build a long chain of thunks;foldl'(fromData.List) forces the accumulator at each step - 26
foldr (-) 0 [1, 2, 3]vsfoldl (-) 0 [1, 2, 3]foldrcomputes1 - (2 - (3 - 0)), which is 2;foldlcomputes((0 - 1) - 2) - 3, which is -6 - 27Why can
foldrstop early on an infinite list?It passes the rest of the fold to the function as a lazy argument, so a function that doesn’t use it ends the foldhaskellfoldr (\x acc -> x > 10 || acc) False [1 ..] -- True - 28What does
[x * 2 | x <- [1 .. 10], even x]produce?[4,8,12,16,20]: a list comprehension with a generator and a filter - 29The definition of
Maybehaskelldata Maybe a = Nothing | Just aIt models a value that may be missing, where other languages use null. - 30Which side of an
Eitherholds the error?Left, by convention;Rightholds the success value, andfmapand>>=only act onRight - 31Get the value out of a
Maybe, with a defaultfromMaybe 0 m(fromData.Maybe), ormaybe 0 f mto also transform aJustvalue withf - 32Why avoid
head?It’s partial:head []throws an exception. Pattern match instead, or uselistToMaybeor aNonEmptylistGHC 9.8 and later warn when you useheadortail(-Wx-partial). - 33What does
fmapdo?Applies a function inside a structure without changing its shape:fmap (+ 1) (Just 2)isJust 3, andfmap (+ 1) NothingisNothing<$>isfmapas an operator:(+ 1) <$> Just 2. - 34What is
fmap (+ 1) (1, 2)?(1,3): theFunctorinstance for pairs maps only the second componentFor the same reason,length (1, 2)is 1. - 35What does
(+) <$> Just 3 <*> Just 4return?Just 7:(+) <$> Just 3isJust (3 +), and<*>applies that wrapped function toJust 4If either argument isNothing, the result isNothing. - 36What does
[(+ 1), (* 2)] <*> [10, 20]return?[11,21,20,40]: the listApplicativeapplies every function to every value - 37How are
Functor,ApplicativeandMonadrelated?EveryMonadis anApplicative, and everyApplicativeis aFunctor: each class is a superclass of the next - 38The type of
>>=(>>=) :: Monad m => m a -> (a -> m b) -> m bIt feeds the result of one action into a function that chooses the next action. - 39Does
returnend a function early?No.return x(the same aspure x) only wrapsxin the monad; thedoblock carries on with the next line - 40How does a
doblock desugar?do { x <- m; rest }becomesm >>= \x -> do { rest }, anddo { m; rest }becomesm >> do { rest } - 41
x <- actionvslet x = valuein adoblock<-runs a monadic action and binds its result;letbinds a plain value, with noinhaskellmain = do name <- getLine let greeting = "Hi, " ++ name putStrLn greeting - 42What does this return?haskell
do a <- Just 1 b <- Nothing pure (a + b)Nothing: in theMaybemonad, the firstNothingshort-circuits the rest of the block - 43Parse a list of strings, failing if any one failshaskell
traverse readMaybe ["1", "2", "x"] :: Maybe [Int] -- NothingreadMaybecomes fromText.Read. With["1", "2"]the result isJust [1,2]. - 44
mapMvsmapM_mapMruns an action for each element and collects the results;mapM_runs them only for their effects and returns()forM_(fromControl.Monad) ismapM_with its arguments flipped:forM_ [1 .. 3] print. - 45How do you use the
Stringinside anIO String?Bind it inside anotherIOaction with<-(or>>=) and pass it to pure functions from there; pure code can’t runIOactions - 46What does
$do inprint $ sum [1, 2, 3]?It is function application with the lowest precedence, so it replaces parentheses:print (sum [1, 2, 3]) - 47Function composition with
.(f . g) xisf (g x), socountWords = length . wordsdefines a function without naming its argument - 48What does
zipWith (+) [1, 2, 3] [10, 20]return?[11,22]:zipWithstops at the end of the shorter list - 49Sort a list of pairs by their second element
sortOn snd pairs(fromData.List)sortBy (comparing snd) pairsdoes the same, withcomparingfromData.Ord. - 50Look up a key in a
Data.Maphaskellimport qualified Data.Map.Strict as Map Map.lookup "ada" (Map.fromList [("ada", 36)]) -- Just 36A missing key givesNothing.
Frequently asked questions
Do I need to know another functional language first?
No, but it helps to have worked through an introductory tutorial: the cards assume you can read a basic function definition.
Which version of Haskell does it use?
Standard Haskell as compiled by current GHC releases, with functions from base such as Prelude, Data.List, Data.Maybe and Text.Read. The Data.Map card uses the containers package.
Is this a monad tutorial?
Not quite. It drills what fmap, <*>, >>= and do-notation do with Maybe, Either, lists and IO, which is what you need to read and write everyday Haskell.
More in Programming
JavaScript
Master the JavaScript every developer uses daily: scope, closures, equality, array methods, promises, async/await and the event loop.
50 cardsAdvanced JS
Fifty advanced JavaScript cards: event-loop ordering puzzles, generators and async iteration, this binding, Proxy and Reflect, modules, AbortController and coercion edge cases.
50 cardsTypeScript
Learn the TypeScript you use every day: narrowing, generics, keyof, mapped and conditional types, utility types, satisfies and strict mode, with code on every card.
50 cardsPython
Learn idiomatic Python fast: comprehensions, f-strings, args and kwargs, generators, decorators, context managers and the standard library.
50 cardsGit & terminal
The Git commands and shell skills developers use every day: branching, rebasing, undoing mistakes, pipes, redirects, permissions and processes.
50 cardsJava
Core Java with short snippets: equals vs ==, records, sealed types, collections, generics, exceptions, streams, lambdas and JVM basics.
50 cardsC#
C# and .NET fundamentals with short snippets: value vs reference types, properties, records, nullable reference types, LINQ, async/await and DI.
50 cardsKotlin
Kotlin fundamentals with short snippets: null safety, val vs var, data and sealed classes, extension functions, scope functions and coroutines.
50 cardsSwift
Swift fundamentals with short snippets: optionals, structs vs classes, protocols, enums with associated values, closures, ARC, async/await and SwiftUI.
50 cardsFlutter
Flutter and Dart basics: null safety, futures and streams, stateless vs stateful widgets, setState, hot reload, keys, layout and state management.
50 cardsPHP
Modern PHP 8 with short snippets: strict types, arrays, match, nullsafe and named arguments, enums, readonly, Composer, PDO and password_hash.
50 cardsRuby
Ruby fundamentals with short snippets: blocks, procs and lambdas, symbols, Enumerable, mixins, truthiness, method_missing, gems and Bundler.
50 cardsGo
Go (Golang) fundamentals with short, idiomatic snippets: slices vs arrays, maps, defer, error wrapping, interfaces, goroutines, channels, select and context.
50 cardsRust
Learn the Rust that the compiler keeps asking about: ownership, borrowing, lifetimes, Option and Result, traits, closures, smart pointers and async.
50 cardsC++
Modern C++ in short snippets: references vs pointers, RAII, smart pointers, move semantics, STL containers and algorithms, const, templates and UB.
50 cardsElixir
Elixir fundamentals with short snippets: immutability, pattern matching, the pipe operator, Enum vs Stream, processes, GenServer, supervisors and mix.
50 cardsx86-64 assembly
x86-64 assembly in Intel syntax: registers and sub-registers, flags, mov and lea, jumps, the stack frame, the System V calling convention and Linux syscalls.
50 cardsRegex
Learn regular expressions for good: anchors, classes, greedy vs lazy quantifiers, groups, lookarounds, flags, replacements and the backtracking trap.
50 cards