Chapters

Hide chapters

Functional Programming in Kotlin by Tutorials

First Edition · Android 12 · Kotlin 1.6 · IntelliJ IDEA 2022

Section I: Functional Programming Fundamentals

Section 1: 8 chapters
Show chapters Hide chapters

Appendix

Section 4: 13 chapters
Show chapters Hide chapters

E. Appendix E: Chapter 5 Exercise & Challenge Solutions
Written by Massimo Carli

Exercise 5.1

Kotlin provides you with first, which returns the first element of Iterable<T> for which a predicate you provide as an input evaluates to true. Remember that Iterable<T> is the abstraction of all the collections providing an Iterator<T> implementation.

public interface Iterable<out T> {
  public operator fun iterator(): Iterator<T>
}

Iterator<T> allows you to iterate over all the elements of a collection in a way that doesn’t depend on the collection implementation itself:

public interface Iterator<out T> {

  public operator fun next(): T

  public operator fun hasNext(): Boolean
}

The current first signature is:

public inline fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T

Kotlin doesn’t allow you to override the current extension function on Iterable<T>. So, how would you implement first on Array<T>?

The current implementation of first throws an exception if the collection is empty, so there’s no first T. How would you implement the function firstOrNull on Array<T> returning null in such a case?

Exercise 5.1 solution

As mentioned, Kotlin doesn’t allow you to override the extension function on Iterable<T> so, for this exercise, you need to implement first on Array<T>. A possible solution is:

public inline fun <T> Array<T>.first(
  predicate: (T) -> Boolean
): T { // 1
  for (item in this) { // 2
    if (predicate(item)) { // 3
      return item // 4
    }
  }
  throw NoSuchElementException("Array contains no element matching the predicate.") // 5
}

The code is quite simple. In it, you:

  1. Define first as an extension function for Array<T>, accepting a predicate as an input parameter and returning a value of type T.
  2. Iterate over the values in Array<T>.
  3. Evaluate the predicate on the current item.
  4. Return the value for which predicate evaluates to true.
  5. Throw a NoSuchElementException if predicate never evaluates to true.

Test first with the following code:

fun main() {
  val input = arrayOf(1, 2, 3, 4, 5)
  println(input.first {
    it > 3  // 1
  })
  println(input.first {
    it > 10 // 2
  })
}

When you run the previous code, you get:

4
Exception in thread "main" java.util.NoSuchElementException: Array contains no element matching the predicate.

Note how:

  1. Passing the predicate { it > 3}, you get the value 4.
  2. Using { it > 30}, you get NoSuchElementException.

What if you don’t want to throw an exception but implement first in a more functional way without NoSuchElementException as a side effect?

A possible solution is the following firstOrNull implementation:

public inline fun <T> Array<T>.firstOrNull(
  predicate: (T) -> Boolean
): T? { // 1
  for (item in this) {
    if (predicate(item)) {
      return item
    }
  }
  return null // 2
}

The code isn’t very different from the first one. Here, you:

  1. Have the optional T? as a return type.
  2. Return null if there’s no value for the given predicate.

Test firstOrNull by running the following code:

fun main() {
  val input = arrayOf(1, 2, 3, 4, 5)
  println(input.first {
    it > 3
  })
  println(input.firstOrNull { // HERE
    it > 10
  })
}

In the previous code, you use firstOrNull instead of first. Run this code, and you get:

4
null

Exercise 5.2

The command pattern is another important design pattern that defines abstractions like Command and CommandExecutor. Command abstracts every possible operation that CommandExecutor can run. In other words, a Command represents a task and you can pass a Command to a CommandExecutor to run it. How would you represent them in a functional way?

Optionally, can you also provide a way to “redo” the most recent Command?

Exercise 5.2 solution

Command is basically a way to abstract the concept of a task. To represent it in a functional way, write:

typealias Command = () -> Unit

CommandExecutor is the component responsible for the execution of Command. A simple way to represent it is:

typealias CommandExecutor = (Command) -> Unit

You can create a possible implementation like the following:

class MyCommandExecutor : CommandExecutor { // 1

  val commandHistory = mutableListOf<Command>() // 2

  override fun invoke(command: Command) { // 3
    command.run {
      commandHistory.add(this)
      this()
    }
  }

  fun redo() { // 4
    commandHistory.lastOrNull()?.let {
      it()
    }
  }
}

In the previous code, you:

  1. Define MyCommandExecutor as an implementation of CommandExecutor.
  2. Initialize commandHistory, which will contain the history of all the commands you execute. This isn’t necessary, but usually, the command pattern allows you to run Command multiple times.
  3. Override invoke, passing Command as a parameter. In the body, you simply invoke Command after saving its reference in commandHistory.
  4. Provide redo() as a chance to execute the last command again.

Usually, the command pattern also allows you to undo Commands, but that’s out of the scope of this book.

Exercise 5.3

Can you implement the following Reader interface as a functional interface? How would you test it?

interface Reader {
  fun readChar(): Char?
  fun readString(): String {
    TODO("Call readChar() until it returns null")
  }
}

Exercise 5.3 solution

The TODO in the problem description’s code gives you a hint about a possible solution. One option is the following:

fun interface Reader {
  fun readChar(): Char?
  fun readString(): String {
    val result = StringBuilder()
    do {
      val nextChar = readChar()
      if (nextChar != null) {
        result.append(nextChar)
      }
    } while (nextChar != null)
    return result.toString()
  }
}

In this code, you’re basically implementing readString using StringBuilder appending Char, which you get from readChar until you get null. In that case, you return what’s in StringBuilder by invoking toString.

So far, so good! But how do you test it? Does making Reader a functional interface help? Actually, it doesn’t.

To test Reader, use the following implementation:

class MyReader(val str: String) : Reader { // 1
  var pos = 0 // 2
  override fun readChar(): Char? =
    if (pos < str.length) str[pos++] else null // 3
}

Here, you:

  1. Create MyReader as a simple implementation of Reader, receiving String as an input parameter.
  2. Initialize pos to 0, which is the position of the first Char you want to return from readChar.
  3. Check if pos is in the boundary of the String provided as input. If so, you return the Char in it and increment pos. Otherwise, you return null.

To test how this works, just run the following code:

fun main() {
  val input = MyReader("This is a String!")
  println(input.readString())
}

Getting:

This is a String!

The initial question remains: What advantage do you have by making Reader a functional interface? It gives you two advantages:

  1. You can use the handy Type { /* lambda */} syntax.
  2. You can pass a Reader implementation instance using a simple lambda expression as an input parameter of another function. In that case, Kotlin would infer the right type.

You could test the first case with the following code:

fun main() {
  val inputString = "This is a String!"
  var pos = 0
  val input = Reader {
    if (pos < inputString.length) inputString[pos++] else null
  }
  println(input.readString())
}

In this case, the Reader implementation captures the value of pos, which basically represents its own state. What if you had the following code instead?

fun main() {
  val inputString = "This is a String!"
  var pos = 0
  val input = Reader {
    if (pos < inputString.length) inputString[pos++] else null
  }
  val input2 = Reader {
    if (pos < inputString.length) inputString[pos++] else null
  }
  println(input.readString())
  println(input2.readString())
}

Only the first println would actually print something. To make things work, you’d need a second variable for the state of Reader for input2, like this:

fun main() {
  val inputString = "This is a String!"
  var pos = 0
  var pos2 = 0
  val input = Reader {
    if (pos < inputString.length) inputString[pos++] else null
  }
  val input2 = Reader {
    if (pos2 < inputString.length) inputString[pos2++] else null
  }
  println(input.readString())
  println(input2.readString())
}

This method is confusing and error-prone.

You’d have the same problem, even if you pass Reader as an input parameter of another function, like this:

fun consumeReader(reader: Reader) {
  println(reader.readString())
}

fun main() {
  var pos = 0
  val inputString = "This is a String!"
  consumeReader({
    if (pos < inputString.length) inputString[pos++] else null
  })
}

The only advantage here is that you don’t need to specify the Reader type before the lambda because the Kotlin compiler infers it for you.

So, what’s the lesson here? As you learned in the chapter, typealias allows you to give a name to an existing type. In the case of function types, you can assume they already exist somewhere, and typealias is a tool to reduce the quantity of code you have to write, especially for generic types. Types like (T)-> Boolean, (T,T) -> T and so on already exist, even if you don’t declare them explicitly.

The type you define using a functional interface is a new type, and the implementations must specify the name explicitly. They don’t exist before that, even if they basically define an existing type. As proved in the chapter, consider the functional interface:

fun interface SinglePredicate<T> {
  fun accept(value: T): Boolean
}

This is basically equivalent to (T)-> Boolean, but it’s a completely different type. The extension function you define for SinglePredicate<T> doesn’t work for (T)-> Boolean, and vice versa. If you have a parameter of type SinglePredicate<T>, you can’t pass a lambda expression of type (T)-> Boolean.

As a last note, remember that typealiases aren’t visible from Java, but functional interfaces are.

Exercise 5.4

Implement an extension function isEqualsPredicate on the generic type T that returns a predicate that tests if a given value is equal to the same T. The signature should be the following:

 fun <T> T.isEqualsPredicate(): (T) -> Boolean //

How would the same function be different if you use the following functional interface?

fun interface SinglePredicate<T> {
  fun accept(other: T): Boolean  
}

Exercise 5.4 solution

A possible solution to the initial problem is the following:

fun <T> T.isEqualsPredicate(): (T) -> Boolean =
  { value -> this == value }

Test this with the following code:

fun main() {
  listOf(1, 2, 3, 4, 4, 5, 6, 7, 8, 8)
    .filter(4.isEqualsPredicate())
    .forEach(::println)
}

Run it, and you get:

4
4

If you use the functional interface SinglePredicate<T>, you have:

fun <T> T.isEqualsIPredicate(): SinglePredicate<T> =
  SinglePredicate<T> { value -> this == value }

Note how the name of the extension function isn’t isEqualsPredicate. This avoids conflicts with the previous one because they’re both acting on the same receiver, T, and not because of the different return type.

Exercise 5.5

Can you implement the same logic for implementing the example in the Imperative vs. declarative approach section using the definitions of Predicate1<T> and filterWithPredicate? Given a list of email addresses, you need to:

  • Filter the valid email addresses.
  • Filter the email addresses with the right length.
  • Take the first five of them.

Exercise 5.5 solution

Using the definitions of Predicate1<T> and filterWithPredicate you have in Predicates.kt and what’s in Imperative.kt and Declarative.kt, you can write:

val isValidEmail: Predicate1<String> = // 1
  Predicate1 { value -> EMAIL_REG_EX.matches(value) }

fun isLongerThan(length: Int): Predicate1<String> = // 2
  Predicate1 { value -> value.length > length }

fun main() {
  emails
    .filterWithPredicate(isValidEmail and isLongerThan(10)) // 3
    .take(5) // 4
    .forEach(::println) // 5
}

In this code, you:

  1. Define isValidEmail as a Predicate1<String> that checks the validity of email addresses.
  2. Create isLongerThan as a function returning a Predicate1<String> that checks the length of String.
  3. Use filterWithPredicate, passing in as input the logic and between isValidEmail and isLongerThan.
  4. Take the first 5 successful email addresses.
  5. Print the result.

Running the previous code, you get:

email@emmmaail.com
mike@mcarli.it
first.second@ggg.com
test@test.co.uk
fp_is_great@funprog.com

Challenge 5.1: Mapping is important

In the chapter, you learned how to implement different types of higher-order functions, and in the next chapter, you’ll see many more. A very important one is called map. This is a function that applies a given function fn of type (A) -> B to all the elements of a collection of items of type A, getting a collection of items of type B.

Can you implement the function map for the Array<A> type with the following signature?

fun <A, B> Array<A>.map(fn: (A) -> B): Array<B>

When you run this code:

fun main() {
  val square = { a: Int -> a * a }
  val toString = { a: Int -> "This is $a" }
  arrayOf(1, 2, 3)
    .map(square)
    .forEach(::println)
  arrayOf(1, 2, 3)
    .map(toString)
    .forEach(::println)
}

You should get:

1
4
9
This is 1
This is 2
This is 3

Challenge 5.1 solution

A possible implementation of map for Array<A> is the following:

inline fun <A, reified B> Array<A>.map(fn: (A) -> B): Array<B> =
  Array(this.size) { fn(this[it]) }

This simply uses the constructor for Array to initialize all the values after applying fn to all the elements in the original array.

Note the use of reified for the type B. This is because the Kotlin compiler needs to retain some information about the type B to properly initialize Array in output.

Running main in the challenge, you get the expected output:

1
4
9
This is 1
This is 2
This is 3

Challenge 5.2: Prime number filtering

Write a higher-order function all returning a new array containing all the values in an Array<T> for which a given Predicate1<T> is true. You can find the Predicate1<T> definition in Predicates.kt.

fun <T> Array<T>.all(predicate: Predicate1<T>) : Array<T>

Then, use it to return all the positive prime values in Array<Int>. A number is prime if it’s not evenly divisible with any number other than 1 and itself.

Challenge 5.2 solution

You can implement all in many different ways. One of them is:

inline fun <reified T> Array<T>.all(
  predicate: Predicate1<T>
): Array<T> = filter { predicate.accept(it) }.toTypedArray()

You leverage the existing filter, adapting Predicate1<T> to the type (T) -> Boolean it requires. Then, you use toTypedArray() to make the List<T> an Array<T>. This requires more type information and is the reason for the reified keyword.

The following is a possible implementation of Predicate1<Int> testing if a given Int is a prime number:

val isPrime = Predicate1<Int> { value ->
  if (value <= 3) value > 1
  else if (value % 2 == 0 || value % 3 == 0) false
  else {
    var i = 5
    while (i * i <= value) {
      if (value % i == 0 || value % (i + 2) == 0)
        return@Predicate1 false
      i += 6
    }
    true
  }
}

This predicate tests if the Int is a prime number or not.

Finally, you can test it with:

fun main() {
  arrayOf(1, 45, 67, 78, 34, 56, 89, 121, 2, 11, 12, 13)
    .all(isPrime)
    .forEach(::println)
}

Running the previous code, you get:

89
2
11
13
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.