B
Appendix B: Chapter 2 Exercise & Challenge Solutions
Written by Massimo Carli
Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as
text.You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.
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?
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 Set
s 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:
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
}
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!