Based on the code snippets developed in class, summaries and explanations in this document were drafted with the assistance of generative AI. The author verified all facts, revised the text for coherence, and takes full responsibility for the final content.
Week 3 Overview
Week 3 covers statements and expressions, strict and non-strict evaluation, functions on lists, methods and functions, and folds. The snippets move from methods to function values, then to higher-order functions, currying, and folds, and close with the evaluation strategy of function arguments: call-by-value versus call-by-name.
1. From Methods to Functions
A good starting point is to compare a method definition in an object with a function value.
object Methods:
val x = 5
def add(y: Int, z: Int) = x + y + z
end MethodsThe method add is part of object structure and can use object fields (x). Now compare that with a function value:
val add: (Int, Int) => Int =
(x: Int, y: Int) => x + y
val add2: (Int, Int) => Int =
(_: Int) + (_: Int)This difference is emphasized in the currying slides: methods organize behavior in class/object structure, while functions are first-class values that can be passed, returned, and stored.
Scala 3 Book pointers: - Methods: https://docs.scala-lang.org/scala3/book/methods-main-methods.html - Functions: https://docs.scala-lang.org/scala3/book/fun-intro.html - Anonymous functions: https://docs.scala-lang.org/scala3/book/fun-anonymous-functions.html
Practical relevance: In larger systems, methods are useful for stable APIs, while function values make extension points easy (custom sorting, callbacks, validation pipelines, strategy selection).
2. Higher-Order Functions: Passing Behavior
Once functions are values, we can pass behavior into generic code:
def g(x: Int, y: Int, f: (Int, Int) => Int) =
f(x, y)
end g
g(1, 2, _ + _)
g(1, 2, (x, y) => x + y)We can also return functions from functions:
def createAdd(): (Int, Int) => Int =
val result: (Int, Int) => Int =
(x: Int, y: Int) => x + y
result
end createAdd
val sum: Int = createAdd()(3, 4)This is the core idea of higher-order programming from the functional-programming and currying lectures: separate traversal or orchestration logic from the specific operation.
Scala 3 Book pointers: - Higher-order functions: https://docs.scala-lang.org/scala3/book/fun-hofs.html
Practical relevance: This style scales well in production code because shared infrastructure can remain unchanged while business rules are injected as function arguments.
3. Currying and Partial Application
Next, the snippet introduces a curried version of addition:
val addCurried: Int => Int => Int =
(x: Int) =>
(y: Int) =>
x + y
val sum2: Int = addCurried(1)(2)With collections, this enables partial application:
List(1, 2, 3).map(x => x + 1)
List(1, 2, 3).map(add(_, 1))
List(1, 2, 3).map(addCurried(1))The demonstrated insights from the slides are: tupled multi-argument style and curried single-argument-chain style are both useful, and partial application creates specialized functions from general ones.
Scala 3 Book pointers: - Eta expansion and partially applied functions: https://docs.scala-lang.org/scala3/book/fun-eta-expansion.html - Methods and functions in practice: https://docs.scala-lang.org/scala3/book/methods-main-methods.html
Practical relevance: In larger software efforts, currying and partial application reduce repetition in data processing and request handling where one or two parameters stay fixed across many calls.
4. Folds as a Unifying Pattern for Aggregation
The fold slides emphasize that many list aggregations differ only by: 1. an initial value 2. a combining function
The code snippet shows this directly:
def sum(xs: List[Int]) =
xs.foldLeft(0)(_ + _)
def prod(xs: List[Int]) =
xs.foldLeft(1)(_ * _)
def or(xs: List[Boolean]) =
xs.foldLeft(false)(_ || _)
def and(xs: List[Boolean]) =
xs.foldLeft(true)(_ && _)And list append through a right fold:
def append(xs: List[Int])(ys: List[Int]) =
xs.foldRight(ys)(_ :: _)Once behavior is a function parameter, we can abstract over list traversal and keep only the aggregation intent.
Scala 3 Book pointers: - Collections methods (map, foldLeft, foldRight): https://docs.scala-lang.org/scala3/book/collections-methods.html - Lists and immutable data: https://docs.scala-lang.org/scala3/book/collections-classes.html
Practical relevance: Teams use folds to avoid ad hoc loops and duplicated boilerplate. The resulting code is easier to test, review, and optimize because each aggregator states exactly what it computes.
5. Call-by-Value and Call-by-Name
The strict/non-strict lecture ends on how a function argument is evaluated. With call-by-value, the argument is evaluated once before entering the function.
def f(x: Double) : Double =
val x1 = x
val x2 = x
x1 - x2
end f
f(Math.random())With call-by-name (=>), each use can re-evaluate the argument expression.
def g(x: => Double) : Double =
val x1 = x
val x2 = x
x1 - x2
end g
g(Math.random())Because Math.random() may run twice in g, the result is not guaranteed to be 0. A call-by-name parameter is a thunk: the argument travels unevaluated and is evaluated at each use, which is what makes user-defined non-strict constructs possible. We pick this up again in week 6, where argument passing is compared across languages.
Scala 3 Book pointers: - Control structures and function arguments: https://docs.scala-lang.org/scala3/book/control-structures.html
Practical relevance: By-name arguments let a library defer or skip expensive work — logging that formats its message only when the level is enabled, assertions, and custom control constructs.
Summary
Week 3 connects three core ideas:
- Functions are values, so behavior can be passed and returned.
- Folds capture reusable aggregation patterns over collections.
- The evaluation strategy of an argument decides when, and how often, its expression runs.
This progression is central to building scalable functional components: concise APIs, reusable behavior, and predictable evaluation.