In-class-7 Test Review 1
This guide is here to help you review what we’ve covered so far in CSCE 314 before the midterm. Each section highlights key concepts, examples, and short review questions drawn from our weekly lectures. Use this as a way to refresh your understanding of Haskell’s functional programming foundations and how these ideas connect together.
Week 1 – History & Functional Programming Primer
Functional programming (FP) emerged as an alternative to imperative programming, emphasizing expressions and results rather than sequences of steps. FP languages like Haskell are based on mathematical functions and avoid mutable state.
- Immutability: you cannot change a value after you have assigned it.
- If we need another value in functional programming we typically create another variable
- Focuses on what to compute, not how to compute
- Functional programming vs. Imperial programming:
- Not global variables, no states
total = sum arr -- Declarative: describe what, not how
Review Questions:
- What are the key differences between imperative and functional programming?
- Imperative programming changes state step-by-step with commands; functional programming avoids state changes and builds results by applying pure functions.
- Why does Haskell use expressions rather than statements?
- Because every construct in Haskell must produce a value — it emphasizes what to compute, not how to execute.
Week 3 – Algebraic Data Types (ADTs), Pattern Matching, Tuples, Guards
Algebraic Data Types (ADTs) allow us to define custom types that model real-world concepts directly. Pattern matching provides a clear, readable way to deconstruct these types.
data Shape = Circle Float | Rectangle Float Float
area (Circle r) = pi * r^2
area (Rectangle w h) = w * h
Review Questions:
- How do ADTs make programs more expressive?
- ADTs (Algebraic Data Types) let you define custom types that model real-world concepts precisely, combining different shapes of data under one clear structure.
- What does the underscore (
_) mean in a pattern match?- It’s a wildcard — it matches any value but ignores it (doesn’t bind it to a name).
- Tuples:
- It is a group of items
- A way of pairing different types of items together
- Any amount of elements except for one, you cannot have a tuple of 1 item but you can have an empty tuple.
- Guards:
- Alternative to if-statements
- You can use these guards to protect the data from out of bounds values.
Week 4 – Recursion, Higher-Order Functions, Lambdas, Currying, Lists
Recursion follows the shape of data. Higher-order functions take or return other functions. Lambdas are anonymous functions, and currying lets you apply arguments one at a time.
- Higher order functions take and return other functions
- You can give and return a function
- Recursion takes a base case and a recursive call.
- The two things that you plan for
- The terminating case is when something kind of went wrong, for example infinite recursion or something that pops you out of a loop
- What is currying?
- Maybe you don't know the second input yet, or it maybe be supplied by later calls of other functions.
- Difference between explicitly returning a function and currying
sumList [] = 0
sumList (x:xs) = x + sumList xs
map (\x -> x * 2) [1..5] -- Example of lambda use
Review Questions:
- What are the base and recursive cases in a list recursion?
- The base case handles the empty list (
[]), and the recursive case processes the head (x) and recursively calls the function on the tail (xs).
- The base case handles the empty list (
- How does currying simplify function definitions?
- Currying lets functions take arguments one at a time, enabling easy partial application and cleaner composition of smaller functions.
Week 5 – Polymorphism and Type Classes
Polymorphism allows functions to operate on values of many types. Type classes provide constraints, such as Eq for equality or Ord for ordering.
- What does polymorphism allows you to do?
- Allows you to have generic data times, but sometimes it is restricted
- That idea that you can say "any data type is fine" for a specific function.
length :: [a] -> Int
length [] = 0
length (_:xs) = 1 + length xs
instance Eq Shape where
(Circle r1) == (Circle r2) = r1 == r2
_ == _ = False
- Allows you to check for the length, ignoring each item, we just add one when encoutering each item, no matter what it is.
Review Questions:
- What does it mean for a Haskell function to be polymorphic?
- It means the function can operate on multiple types, using type variables (like
a,b) instead of a fixed type.
- It means the function can operate on multiple types, using type variables (like
- How are type classes similar to interfaces in OOP?
- Both define a set of required behaviors — a type class specifies functions a type must implement, just like an interface defines methods a class must provide.
Week 6 – Laziness and Infinite Structures
Haskell uses lazy evaluation—values are computed only when needed. This enables infinite structures like streams and sequences.
- Infinite lists behave like generators, not full objects.
naturals = [0..]
take 10 naturals -- [0,1,2,3,4,5,6,7,8,9]
drop 5 [0..] -- Skips the first 5 elements of an infinite list
Review Questions:
- How does lazy evaluation make infinite lists possible?
- Lazy evaluation computes values only when needed, so Haskell can represent infinite lists without evaluating them fully.
- What does the drop function do conceptually?
- It skips a given number of elements from the start of a list and returns the rest.
Week 7 – Trees in Functional Programming
Trees represent hierarchical data naturally in functional programming. Algebraic data types let us define recursive tree structures cleanly.
data Tree a = Leaf a | Node (Tree a) (Tree a)
height (Leaf _) = 1
height (Node l r) = 1 + max (height l) (height r)
inorder (Leaf x) = [x]
inorder (Node l r) = inorder l ++ inorder r
Review Questions:
- What is structural recursion, and how does it apply to trees?
- It is just like a list, instead that it knows the tree has more structure to it, more things to evaluate.
- Structural recursion breaks a structure into smaller parts of the same type; for trees, it processes a node and recursively calls itself on each subtree.
- How can the same tree structure represent different meanings (e.g., binary search vs. expression tree)?
- You can have a tree of students, and you can one find out how many student we have by counting the nodes
- What function would do this?
foldfor trees.
- What function would do this?
- What if I wanted to double the value of a tree?
fmap- Produces a new tree exact same shape, with all numbers doubled,
- Not changing, but creating a second structure.
- The data shape is the same, but the interpretation of nodes and values changes — one models data order, the other models computation.
- You can have a tree of students, and you can one find out how many student we have by counting the nodes
Key Takeaways
Weeks 1–7 have built up a foundation in functional thinking, covering recursion, data abstraction, polymorphism, laziness, and structured data. These ideas combine to show how Haskell models computation through expressions and transformations rather than commands.