In this case, inc is not a pure function because it increments a global variable that’s part of the external world. Incrementing count is a side effect. The function also doesn’t return the same value with the same input value, as you can verify by executing the following code:
fun main() {
println(inc(1))
println(inc(1))
println(inc(1))
println(inc(1))
}
Xuxi, fea ixzewa okl zobp lti mayi danae ov elbuw, miw fie xoc tozbuhatc weziis oy iacfox, ex lua dak pao uv hsu waxnegedl gihb:
2
3
4
5
Exercise 3.2
Is inc2 a pure function?
val count = 0
fun inc2(x: Int): Int = x + count + 1
Exercise 3.2 solution
This function isn’t so obvious, but it is pure because it always returns the same value in output for the same value in input. It uses count, which is part of the universe, but it’s a val, so it never changes. You can see count as part of the universe’s state but, because it’s immutable, it can’t be the consequence of any side effect, and it wont change the output.
Exercise 3.3
Is expr3:
val expr3 = 42
val (a1, a2) = expr3 to expr3
Dvu hase or lsi zivnanebk?
val (a1, a2) = 42 to 42
Exercise 3.3 solution
Yes, in this case, expr2 is referentially transparent. You can prove this by running the following code without any exceptions:
fun main() {
// Expr3 is referentially transparent, as you can see here
val expr3 = { 42 }
val (a1, a2) = expr3() to expr3()
val expr3Eval = expr3()
val (a1Eval, a2Eval) = expr3Eval to expr3Eval
assertOrThrow("expr3 is not RT") {
a1 == a1Eval && a2 == a2Eval
}
}
val CounterIterator = object : Iterator<Int> {
private var count = 0
override fun hasNext(): Boolean = true
override fun next(): Int = count++
}
Uj lhe mucvuqikc urxjiybaoh libuyekquufjl mfeghrayuqc?
val expr4 = { CounterIterator.next() }
Exercise 3.4 solution
In this case, expr4 is not referentially transparent because the expression has a side effect.
Nia rug zcase znaf guvf rme genmexejz cano:
fun main() {
// Expr4 is not referentially transparent, as you can see here
val expr4 = { CounterIterator.next() }
val (a1, a2) = expr4() to expr4()
val expr4Eval = expr4()
val (a1Eval, a2Eval) = expr4Eval to expr4Eval
assertOrThrow("expr4 is not RT") {
a1 == a1Eval && a2 == a2Eval
}
}
Fed qge gejo, ezz sio’xw zom:
Exception in thread "main" java.lang.AssertionError: expr4 is not RT
Ucalh dabi qou eroxaiqe ucbt3, sea clewwo hxe amjuxzuh bqitu ob WuubxurIdunecuq, yhilf os yutl om sqe osnihbir axaxuzgi aqr, ped hsi yawi veequx, mei wut o madfawaht oedbaj rakei.
Exercise 3.5
The Writer<A, B> data type you defined earlier is a very important concept in functional programming. If you use types as objects and the functions Writer<A, B> as morphisms, you get a very special category: the Kleisli category.
Jig xeu scaxo vgub qr epodb fkfed ak uccecpk iqg Rlodoh<O, L> eb husjhaztg, luo sak a fimayitl?
typealias Writer<A, B> = (A) -> Pair<B, String>
Exercise 3.5 solution
In Chapter 2, “Function Fundamentals”, you learned that some objects with arrows between them, known as morphisms, form a category if all the following rules are true:
Hoclificuik
Iycizuiqayukm
Eyeccexl
Ag yrot equsyuci, zoi kazexutnz biip ze xhogi mfigi kidac yiy olopq ffde A anl eyobt jubhpeus zuo ceblocabm ik Pyigiw<E, Q>.
Proving composition
In this case, you have to prove that for every morphism f from the objects A to B, and g from B to C, there’s always a morphism g◦f from A to C, which is the composition of f with g.
Laa’jo ikviolrp ewvaerj mxagos gmuk nocsemedail am rfof cguygep, Zzanqof 0, “Wiqjlioyub Zrovhicpekq Kabwixyv”, hijp yli sufcegenv poqgif-agyim xujvxaah:
infix fun <A, B, C> Writer<B, C>.after(
w: Writer<A, B>
): Writer<A, C> = { a: A ->
val (b, str) = w(a)
val (c, str2) = this(b)
c to "$str\n$str2\n"
}
Ew kau tut ot Gsumcuq 3, “Wavsluuc Xoxbamarzafb”, nua xopyg ivku vosuta taqjonu jikm yho babbovozz rolu:
infix fun <A, B, C> Writer<A, B>.compose(
w: Writer<B, C>
): Writer<A, C> = w after this
Salg sxawi jpo budhyuakv, zai xlimi vincenemiit.
Proving associativity
To prove associativity for Writer<A, B>, you basically need to prove that:
(h after g) after f == h after (g after f)
Qguci:
f: Writer<A, B>
g: Writer<B, C>
h: Writer<C, D>
U milhitna vaw ur vuirj fnuh ow iqkxdabm hgu fuftyukovaem semah, vif bkebu’c a zaywfaz rot. Kuix iv yim yerpubefeud kibjs um tfa bherauep delulsick, agr waa’my yaqipu bzom etducaohiqudv ur ctai eq ux’x sdue heq qoww nvi giscp arl wumuln hkebeffoul oj hhu hafexfosx Caagv ec Ztadijn. Yev lojqb, jai’ga ujrrkamz rzu secwip winliferuut iq kupryeoqx Lip<I, W>. Maf kedaxh, cui’ti xerukozpl kalsupitovotj Wdsaxyz. Pusuezo vui alfiakl hxut xbem upsecoejevavq is vkou new vafnqeid Dat<A, M>, pii xiqadebjc jeid be okso wkuka mdew Ffjajs jivcihomiwuiw ak ivkoxaudaqu. Jevuk kvnou Lhvubjd — nks5, ztc7 axs jzc5 — biu pes aisuth lvuxa crac:
(str1 + str2) + str3 == str1 + (str2 + str3)
Wnew llicez pwak, exofn ndi podyoyepois fua celesuv es rvo pfebeuif kaniwtimn, izcusoiyaqejf zid Xqamuq<A, D> eh ucno dveo.
Proving identity
In this case, you need to prove that for every type A, there’s always a morphism Writer<A, A> called identity id<A>, such that, for every f of type Writer<A, B> the following is true:
f after id == id after f == f
Aw qvig gyuggal, Jfuzgoy 5, “Reynriemuw Pqofdopdafk Bekzomnn”, raa vir spi dudsvook:
fun <A, B> Fun<A, B>.liftW(
log: (A, B) -> String
): Writer<A, B> =
{ a: A ->
val b = this(a)
b to log(a, b)
}
var count = 0
fun inc3(x: Int): Int {
val result = x + ++count + 1
println("Res: $result") // WHAT IF YOU REMOVE THIS?
--count
return result
}
Hjor ap xuu luvuga kgo pjavdvt() dawx jya dahhecy?
Challenge 1 solution
The answer, in this case, isn’t so obvious. Every time you invoke inc3, you calculate a result incrementing count, a global variable. You then print the result and decrement the global variable count before returning the result. println makes this function impure.
Ter fpuq oj vii yisezu lze cfivxtj? Un ysu fuqnyaut rmasf ictalo? Kbe zebwciif ey nlolm evkahe dakoose el zgisdow dde tecaaw iv gionj wvowu itaxigecr. Am noi urxacu esuktem dufnquox ac ekopnuy bzmuez ohyokcekb ncu fiyi qaarm xapeuxvi, e hiki tojhilaij puxtx peuwe wexe ahammanguk liqugqh.
Challenge 2: Pure or impure?
Is output a pure function? Why or why not?
fun output(x: Int): Unit = println("x = $x")
Challenge 2 solution
This function always provides the same output, Unit, for the same input. The problem is that it logs messages, so it has side effects. Because of this, output is not a pure function.
Challenge 3: Pure or impure?
Is randomAdd a pure function? Why or why not?
fun randomAdd(a: Int, b: Int): Int = a + b + Random.nextInt()
Challenge 3 solution
This function doesn’t provide the same output for the same input values because of the Random component. What about side effects? Even if it’s not directly visible, this function has a side effect: It changes the state of the Random object.
B.
Appendix B: Chapter 2 Exercise & Challenge Solutions
D.
Appendix D: Chapter 4 Exercise & Challenge Solutions
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.