Lambdas Workbook (Part 1): The Basics

Twelve short exercises on the lambda basics — defining and calling, parameters and results, function types, the implicit it, and multi-line bodies.

Practice problems for A Kotlin Lambda Is a Value You Can Pass Around. Each takes a minute or two. Several exercises auto-check: implement the lambda in the editor and press Run — hidden tests go green when you’re right and red (with a hint) when you’re not, on JetBrains’ Kotlin server. The rest — the ones that print, and the pure syntax questions — stay attempt-then-reveal: press Run to try them, then click Show answer. Nothing here is a trick question, just direct practice of the syntax from the lesson.

defining and calling

1. Store and run

Store a lambda that prints "hi" in a variable greet, then run it.

Try it — edit, then press Run fun main() { val greet = { println("") } // TODO: make it print "hi" greet() }
Show answer Hide answer
val greet = { println("hi") }
greet()

2. Defining isn’t running

Given val greet = { println("hi") }, write the single line that actually runs the code inside.

Try it — edit, then press Run fun main() { val greet = { println("hi") } // TODO: write the one line that actually runs greet println("nothing runs until you call greet") }
Show answer Hide answer
greet()

Defining the lambda prints nothing; only calling it does.

3. One parameter

Write a lambda welcome that takes a String name and prints Welcome, <name>, then call it with "Ada".

Try it — edit, then press Run fun main() { val welcome = { name: String -> println("Welcome, ") } // TODO: include name welcome("Ada") }
Show answer Hide answer
val welcome = { name: String -> println("Welcome, $name") }
welcome("Ada")

results

4. Return a number

Implement the lambda square so it returns its Int argument multiplied by itself.

Implement it, then press Run to check import org.junit.Test import org.junit.Assert class Test { @Test fun square() { Assert.assertEquals("multiply the argument by itself", 25, square(5)) Assert.assertEquals("works for another value", 16, square(4)) } } //sampleStart val square = { x: Int -> 0 } // TODO: return x times itself //sampleEnd
Show answer Hide answer
val square = { x: Int -> x * x }

The last expression in the body is the result — no return.

5. Return a String

Implement the lambda shout so it returns its String argument uppercased with a ! appended.

Implement it, then press Run to check import org.junit.Test import org.junit.Assert class Test { @Test fun shout() { Assert.assertEquals("uppercase and append a bang", "HI!", shout("hi")) Assert.assertEquals("a single letter", "A!", shout("a")) } } //sampleStart val shout = { s: String -> s } // TODO: uppercase s and append "!" //sampleEnd
Show answer Hide answer
val shout = { s: String -> s.uppercase() + "!" }

6. Return a Boolean

Implement the lambda isAdult so it returns whether an Int age is at least 18.

Implement it, then press Run to check import org.junit.Test import org.junit.Assert class Test { @Test fun isAdult() { Assert.assertTrue("18 is an adult", isAdult(18)) Assert.assertFalse("17 is not", isAdult(17)) } } //sampleStart val isAdult = { age: Int -> false } // TODO: true when age is at least 18 //sampleEnd
Show answer Hide answer
val isAdult = { age: Int -> age >= 18 }

7. A multi-line body

Write a lambda grade taking an Int score: on the first line compute "pass" or "fail", and make "Result: <that>" the last line.

Try it — edit, then press Run fun main() { val grade = { score: Int -> // TODO: set outcome to "pass" or "fail", then make "Result: " + outcome the result "Result: " } println(grade(72)) }
Show answer Hide answer
val grade = { score: Int ->
    val outcome = if (score >= 50) "pass" else "fail"
    "Result: $outcome"
}

function types and it

8. Read a type

Write the function type of a lambda that takes two Ints and returns an Int.

Show answer Hide answer
(Int, Int) -> Int

9. Declare with an explicit type

Declare val add with type (Int, Int) -> Int whose body adds its two arguments.

Try it — edit, then press Run fun main() { val add: (Int, Int) -> Int = { a, b -> 0 } // TODO: add a and b println(add(2, 3)) }
Show answer Hide answer
val add: (Int, Int) -> Int = { a, b -> a + b }

With the type on the left, you can drop the parameter types inside the braces.

10. The it shortcut

Rewrite the lambda { n: Int -> n > 0 } using the implicit single-parameter name.

Try it — edit, then press Run fun main() { val positive: (Int) -> Boolean = { n -> n > 0 } // TODO: rewrite the body using 'it' println(positive(5)) }
Show answer Hide answer
{ it > 0 }

11. No input, no output

Write a lambda of type () -> Unit that prints tick.

Try it — edit, then press Run fun main() { val tick: () -> Unit = { println("") } // TODO: print "tick" tick() }
Show answer Hide answer
val tick: () -> Unit = { println("tick") }

12. Drop the parameter type

Given val negate: (Boolean) -> Boolean = { ... }, supply a body that flips the boolean — without writing the parameter’s type.

Try it — edit, then press Run fun main() { val negate: (Boolean) -> Boolean = { b -> b } // TODO: flip b, no parameter type println(negate(true)) }
Show answer Hide answer
val negate: (Boolean) -> Boolean = { b -> !b }

Going deeper: invoke, nullable functions, and type aliases

12. Call a maybe-absent function

A callback that might not be set has a nullable function type. Implement applyOrZero so it calls f on x when f is present, and returns 0 when f is null.

Implement it, then press Run to check import org.junit.Test import org.junit.Assert class Test { @Test fun applyOrZero() { Assert.assertEquals(10, applyOrZero({ n: Int -> n * 2 }, 5)) Assert.assertEquals(0, applyOrZero(null, 5)) } } //sampleStart fun applyOrZero(f: ((Int) -> Int)?, x: Int): Int = 0 // TODO: call f on x if present, else 0 //sampleEnd
Show answer Hide answer
fun applyOrZero(f: ((Int) -> Int)?, x: Int) = f?.invoke(x) ?: 0

A nullable function type needs ?.invoke(...) — there’s no f?.(x) syntax. Note the parentheses in ((Int) -> Int)?: they make the whole function type nullable.

13. Name a function type

typealias gives a repeated function type a readable name. Given typealias Validator = (String) -> Boolean, what is the type of { it.isNotBlank() } assigned to a Validator, and does typealias create a new type? Reveal to check.

Show answer Hide answer

Its type is (String) -> BooleanValidator is just an alias, interchangeable with the underlying type, not a distinct new type. It exists purely so a signature like List<Validator> reads better than List<(String) -> Boolean>.


Back to the lesson, A Kotlin Lambda Is a Value, or on to part two: lambdas at work.

Comments