K
Appendix K: Chapter 12 Exercise 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 12.1
Can you find an example of a monoid whose operation isn’t commutative?
Exercise 12.1 solution
A typical example of a monoid in programming that isn’t commutative is:
a + (b + c) = (a + b) + c
a + b != b + a
fun main() {
val str1 = "Hello"
val str2 = " World!"
println(str1 + str2)
println(str2 + str1)
}
Hello World!
World!Hello
fun main() {
// ...
val unit = ""
println(str1 + unit)
println(unit + str1)
}
Hello
Hello
Exercise 12.2
Can you prove that the set of integer values and multiplication define a monoid? In this case, what would the unit element be?
Exercise 12.2 solution
To prove that the set of integer values and multiplication form a monoid, you have to prove that:
a * (b * c) = (a * b) * c
a * 1 = a
1 * a = a
fun main() {
val a = 3
val b = 7
val c = 13
val res1 = a * (b * c)
val res2 = (a * b) * c
println(res1)
println(res2)
val unit = 1
val res3 = a * unit
val res4 = unit * a
println(res3)
println(res4)
}
273
273
3
3
Exercise 12.3
How would you implement the monoid MonoidIntMult
for Int
and multiplication?
Exercise 12.3 solution
The implementation of MonoidIntMult
is simple because it’s similar to MonoidIntAdd
, which you saw in the chapter. Follow that pattern, and you can implement MonoidIntMult
like this:
object MonoidIntMult : Monoid<Int> { // 1
override val unit: Int
get() = 1 // 2
override val combine: Int.(Int) -> Int
get() = Int::times // 3
}
Exercise 12.4
How would you implement the monoid MonoidStringConcat
for String
and String
concatenation?
Exercise 12.4 solution
As mentioned in the chapter, String
concatenation is an example of a monoid with an operation that isn’t commutative. The implementation of MonoidStringConcat
isn’t so different from MonoidIntAdd
. A possible implementation is:
object MonoidStringConcat : Monoid<String> { // 1
override val unit: String
get() = "" // 2
override val combine: String.(String) -> String
get() = String::plus // 3
}
Exercise 12.5
In the chapter, you proved that addition is different from multiplication using op(op(a, 1), 1)
and op(a, 2)
. The two expressions are equal for any Int
a
if op
is addition, but the same isn’t true if op
is multiplication. Can you implement a Property<Int>
implementation for this rule and use it to create a new test?
Exercise 12.5 solution
Following the pattern you used previously in the chapter, a possible implementation is the following:
class DoubleIncrementProperty : Property<Int> { // 1
override fun invoke(
gen: Generator<Int>,
fn: (List<Int>) -> Int
): Boolean { // 2
val randomValue = gen.generate(1)[0] // 3
val res1 = fn(listOf(fn(listOf(randomValue, 1)), 1)) // 4
val res2 = fn(listOf(randomValue, 2)) // 5
return res1 == res2 // 6
}
}
class PropertyTestTest {
@Test
fun `Exercise 5 solution`() {
100.times {
val additionProp =
CommutativeProperty<Int>() and
DoubleIncrementProperty() and
IdentityProperty(0)
val evaluation = additionProp(IntGenerator) {
sum(it[0], it[1])
}
Truth.assertThat(evaluation).isTrue()
}
}
}