Lambdas Workbook (Part 3): Closures


Practice problems for Closures: What a Lambda Remembers. Each takes a minute or two. Write your own answer first, then click Show answer — nothing here is a trick question, just direct practice of the ideas from the lesson.

capturing

1. Capture a parameter

Write aboveThreshold(numbers: List<Int>, limit: Int) that returns the elements greater than limit — the lambda captures limit.

Show answer Hide answer
fun aboveThreshold(numbers: List<Int>, limit: Int) =
    numbers.filter { it > limit }

2. Capture and mutate

Count how many strings in words are blank, using forEach and a captured var counter. (This mutation of a captured variable is exactly what Java forbids.)

Show answer Hide answer
var blanks = 0
words.forEach { if (it.isBlank()) blanks++ }

3. Sum without sum()

Total nums by capturing and updating a var inside forEach.

Show answer Hide answer
var total = 0
nums.forEach { total += it }

stateful lambdas

4. A counter

Write counter(): () -> Int returning a lambda that yields 1, 2, 3, … on successive calls.

Show answer Hide answer
fun counter(): () -> Int {
    var n = 0
    return { ++n }
}

The returned lambda keeps n alive after counter has returned.

5. A configured multiplier

Write multiplierOf(factor: Int): (Int) -> Int returning a lambda that multiplies its argument by the captured factor.

Show answer Hide answer
fun multiplierOf(factor: Int): (Int) -> Int = { it * factor }

val triple = multiplierOf(3)
triple(10)   // 30

6. A remembered greeting

Write greeterFor(name: String): () -> String returning a lambda that greets the captured name.

Show answer Hide answer
fun greeterFor(name: String): () -> String = { "Hello, $name" }

shared and looped capture

7. Two lambdas, one variable

Declare two lambdas, add and reset, that both operate on the same captured var total.

Show answer Hide answer
var total = 0
val add = { x: Int -> total += x }
val reset = { total = 0 }

Both close over the same total, so changes through one are visible through the other.

8. Capture in a loop

Fill a list with three lambdas, each capturing the loop value i from 1..3, so calling them in turn prints 123.

Show answer Hide answer
val printers = mutableListOf<() -> Unit>()
for (i in 1..3) printers.add { print(i) }
printers.forEach { it() }   // 123

Each iteration’s i is a fresh binding, so every lambda keeps its own.

9. Collect into a captured list

Write a lambda collect that appends its Int argument to a captured MutableList<Int> named seen.

Show answer Hide answer
val seen = mutableListOf<Int>()
val collect = { x: Int -> seen.add(x) }

collect(1)
collect(2)
seen   // [1, 2]

10. Tally into a captured map

Count word frequencies into a captured MutableMap<String, Int>, using forEach.

Show answer Hide answer
val freq = mutableMapOf<String, Int>()
words.forEach { freq[it] = freq.getOrDefault(it, 0) + 1 }

11. A counter with reset

Write makeCounter(): Pair<() -> Int, () -> Unit> returning two lambdas — next (yields 1, 2, 3, …) and reset (sets it back to 0) — that share one captured var.

Show answer Hide answer
fun makeCounter(): Pair<() -> Int, () -> Unit> {
    var n = 0
    val next = { ++n }
    val reset = { n = 0 }
    return next to reset
}

Both returned lambdas close over the same n.


Back to the lesson, Closures: What a Lambda Remembers, or on to part four: references, returns, and anonymous functions.

Comments