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

L. Appendix L: Chapter 13 Exercise Solutions
Written by Massimo Carli

Exercise 13.1

How would you make the Optional<T> data type you created in Chapter 9, “Data Types”, a monad?

Exercise 13.1 solution

In Chapter 9, “Data Types” you implemented the Optional<T> type like this:

sealed class Optional<out T> {
  companion object {
    @JvmStatic
    fun <T> lift(value: T): Optional<T> = Some(value)

    @JvmStatic
    fun <T> empty(): Optional<T> = None
  }
}

object None : Optional<Nothing>()
data class Some<T>(val value: T) : Optional<T>()

To give Optional<T> the monad superpowers you initially need to make it a functor by adding the map function, implement it like this:

fun <A, B> Optional<A>.map(fn: Fun<A, B>): Optional<B> =
  when (this) {
    is Some<A> -> Some(fn(this.value))
    is None -> None
  }

In the chapter, you learned that you can implement the fish operator starting from the implementation of the optionalFlatten function, which is a function of type (Optional<Optional<T>>) -> Optional<T>. After that, you just need to implement optionalBind and then optionalFish in the same way you saw in the chapter.

A possible implementation for optionalFlatten is:

fun <T> Optional<Optional<T>>.optionalFlatten(): Optional<T> = when (this) {
  is Some<Optional<T>> -> when (this.value) {
    is Some<T> -> Optional.lift<T>(this.value.value)
    is None -> Optional.empty()
  }
  is None -> Optional.empty()
}

Here, you just return Some<T> if both the Optionals are Some.

Now, you can implement optionalBind like this:

infix fun <B, C> Optional<B>.optionalBind(
  g: Fun<B, Optional<C>>
): Optional<C> =
  map(g).optionalFlatten()

Finally, you can implement optionalFish like this:

infix fun <A, B, C> Fun<A, Optional<B>>.optionalFish(
  g: Fun<B, Optional<C>>
): Fun<A, Optional<C>> = { a: A ->
  this(a).optionalBind(g)
}

Exercise 13.2

What’s the relation between the fish operator, >=>, and flatMap? Can you express the latter in terms of the former for Optional<T>?

Exercise 13.2 solution

The >=> operator for Optional<T> has type:

((A) -> Optional<B>, (B) -> Optional<C>) -> (A) -> Optional<C>

The flatMap has type (Optional<A>, (A) -> Optional<B>) -> Optional<B>.

A possible way to implement flatMap is the following:

fun <A> Optional<A>.lift(value: A): Optional<A> =
  Optional.lift(value) // 1

fun <A, B> Optional<A>.flatMap(fn: Fun<A, Optional<B>>): Optional<B> =
  map(::lift optionalFish fn).optionalFlatten() // 2

In this code, you:

  1. Define lift as an extension function of Optional<A>. Here, you simply invoke the lift you defined as a static function.
  2. Implement flatMap using optionalFish for creating a function composing lift of type (A) -> Optional<A> and g of type (A) -> Optional<B>, getting a function of type (A) -> Optional<B>. If you use the function as a parameter for map, you get a value of type Optional<Optional<B>> that you know how to flatten using optionalFlatten.
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.