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

B. Appendix B: Chapter 2 Exercise & Challenge Solutions
Written by Massimo Carli

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Exercise 2.1

Can you write an example of a function mapping distinct values in the domain to non-distinct values in the range, like f(b) and f(c) in Figure 2.2?

a’ b’ Domain Range f(b) f(a) f(c)
Figure 2.2: A function definition

Hint: Think of a possible way to group values you get as input. A very simple example is to return a Boolean that tells if the value in input is positive or not.

Exercise 2.1 solution

A simple example of a function mapping distinct values in the domain to non-distinct values in the range is:

fun isEven(x: Int): Boolean = x % 2 == 0
fun main() {
  println(isEven(2))
  println(isEven(-2))
  println(isEven(12))
  println(isEven(18))
  println(isEven(19))
  println(isEven(-3))
  println(isEven(1))
  println(isEven(-5))
}
true
true
true
true
false
false
false
false
typealias Predicate<A> = Fun<A, Boolean> // (A) -> Boolean

Exercise 2.2

Can you write the inverse function of twice? What are the domain and range for the inverse function?

fun twice(x: Int) = 2 * x

Exercise 2.2 solution

This exercise isn’t as easy as it looks. If twice has type Fun<Int, Int>, the inverse function should have the same type. This is because if a function has type Fun<A,B>, the inverse should have type Fun<B,A>. You get this by inverting the input type A with the output type B.

fun half(x: Int) = x / 2
half after twice == twice after half
half after twice == half(twice(x)) == (2 * x) / 2 == x
twice after half == twice(half(x)) == 2 * ( x / 2)
x = 0    2 * (x / 2) == 2 * (0 / 2) == 2 * 0 = 0 == x
x = 1    2 * (x / 2) == 2 * (1 / 2) == 2 * 0 = 0 != x
x = 2    2 * (x / 2) == 2 * (2 / 2) == 2 * 1 = 2 == x
x = 3    2 * (x / 2) == 2 * (2 / 2) == 2 * 1 = 2 != x
fun twice(x: Double): Double = 2 * x
fun half(x: Double): Double  = x / 2.0

Exercise 2.3

Can you prove that using Sets as objects and “is a subset of” as morphisms results in a category? In other words, a morphism from set A to set B would mean that A is a subset of B. In that case, what are the initial and terminal objects?

Exercise 2.3 solution

To prove some kinds of objects and morphisms define a category, you need to prove the three fundamental properties:

U X M A W X
Lumeda 2u.6: Tayseniteec uj kujz

A Z Y Y
Safiho 9a.6: Azsoreatihofb iq tikf

Exercise 2.4

In this chapter, you defined after, which allows you to write expressions like:

val formatTwice = g after f
val formatTwice = f compose g

Exercise 2.4 solution

In this case, you need to consider f as the receiver of the function and write the following code:

inline infix fun <A, B, C> Fun<A, B>.compose(
  crossinline g: Fun<B, C>
): Fun<A, C> =
  { a: A ->
    g(this(a))
  }
fun main() {
  val f: Fun<Int, Int> = ::twice
  val g: Fun<Int, String> = ::format
  val formatTwice = f compose g // HERE
  println(formatTwice(37))
}

Exercise 2.5

Can you write an example of an isomorphic function f and its inverse g and prove they always compose to identity?

Exercise 2.5 solution

The following is an example of a function and its inverse:

fun addOne(x: Int) = x + 1

fun removeOne(x: Int) = x - 1
addOne after removeOne = removeOne after addOne = identity
(x - 1) + 1 = 1 + (x - 1) = x

Challenge 1: Functions and sets

How would you represent a specific Set using a function? For instance, how would you represent the set of even numbers with a function? After that, how would you print all the values in the set?

Challenge 1 solution

A Set is something more than a bunch of things because it has some structure. An object can be in the set or not. If an object is in the Set, it must be unique. You can’t have the same object in a Set twice.

typealias Predicate<A> = Fun<A, Boolean>
val evenIntSet: Predicate<Int> = { a: Int -> a % 2 == 0}
fun main() {
  println(" 0  is even?  ${evenIntSet(0)}")
  println(" 9  is even?  ${evenIntSet(-9)}")
  println(" 10 is even?  ${evenIntSet(10)}")
  println(" 3  is even?  ${evenIntSet(3)}")
}
 0  is even?  true
 9  is even?  false
 10 is even?  true
 3  is even?  false
  (Int.MIN_VALUE..Int.MAX_VALUE)
    .filter(evenIntSet)
    .forEach { println(it) }

Challenge 2: Functions and set again

How would you represent the intersection and union of two sets using functions? The intersection is the set of objects that belong to set A and set B, and the union is the set of all objects that belong to set A or set B.

Challenge 2 solution

Suppose you have the following functions for two different sets:

/** The set of all the odd Ints */
val oddIntSet: Predicate<Int> = { a: Int -> a % 2 != 0 }

/** The set of all multiples of 37 */
val multipleOf37: Predicate<Int> = { a: Int -> a % 37 == 0 }
/** The union of the two sets */
fun <A> union(
  set1: Predicate<A>,
  set2: Predicate<A>
): Predicate<A> = { a: A ->
  set1(a) || set2(a)
}
/** The intersection of the two sets */
fun <A> intersection(
  set1: Predicate<A>,
  set2: Predicate<A>
): Predicate<A> = { a: A ->
  set1(a) && set2(a)
}
val oddMultipleOf37Union =
    union(oddIntSet, multipleOf37)
val oddMultipleOf37Intersection =
  intersection(oddIntSet, multipleOf37)

println("1   is in union ${oddMultipleOf37Union(1)}")
println("37  is in union ${oddMultipleOf37Union(37)}")
println("74  is in union ${oddMultipleOf37Union(74)}")
println("100 is in union ${oddMultipleOf37Union(100)}")

println("1   is in intersection ${oddMultipleOf37Intersection(1)}")
println("37  is in intersection ${oddMultipleOf37Intersection(37)}")
println("74  is in intersection ${oddMultipleOf37Intersection(74)}")
println("100 is in intersection ${oddMultipleOf37Intersection(100)}")

Challenge 3: The right domain

Consider the following function:

fun oneOver(x: Int): Double = 1.0 / x

Challenge 3 solution

You probably know from your math in school that the function 1/x doesn’t exist for x = 0. This means that the domain of oneOver is the set represented by all the Int values without 0.

fun oneOver(x: NonZeroInt): Double = 1.0 / x
@JvmInline
value class NonZeroInt private constructor(val value: Int) {
  companion object {
    operator fun invoke(value: Int): NonZeroInt? {
      return when (value) {
        0 -> null
        else -> NonZeroInt(value)
      }
    }
  }
}
fun main() {
  println("1/3 = ${oneOver(NonZeroInt(3))}") // ERROR
}
2.16 - Type Mismatch. Required: NonZeroInt. Found: NonZeroInt?
9.79 - Znxi Yujxebnz. Jodeepet: DijTaliUzs. Taozr: MipWiviIwt?

fun main() {
  println("1/3 = ${oneOver(NonZeroInt(3)!!)}") // COMPILES
}
@JvmInline
value class NonZeroInt(val value: Int) {
  init {
    require(value != 0) { "O is not a value for this type!" }
  }
}
println("1/3 = ${oneOver(NonZeroInt(3))}")
1/3 = 0.3333333333333333
println("1/3 = ${oneOver(NonZeroInt(0))}")
Exception in thread "main" java.lang.IllegalArgumentException: O is not a value for this type!
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.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now