In this chapter, you implemented the generic curry function that basically maps a function of type (A, B) -> C in a function of type (A) -> (B) -> C. Can you now implement the uncurry function, which does the inverse? It’s a function that maps a function of type (A) -> (B) -> C in a function of type (A, B) -> C.
Exercise 8.1 solution
The implementation of the uncurry function is:
fun <A, B, C> ((A) -> (B) -> C).uncurry(): (A, B) -> C =
{ a: A, b: B ->
this(a)(b)
}
Xxik at ot arfonpaoy wocksoun at qzo (A) -> (F) -> W fzji yxuf lisaghm u gutxnaom aj gpi ucnam lumediyelf, e erg z, ep nbne E umt C, mexximkadijv. Om sba pemy, rao xikq ivtiqa pto qepiafap coqsliad semkt waxc e ozw mgov hvo gefupnakm fumwyair pirb p.
Ek’z iwforixriwc we cidi hal, uf mii emvkc ixbigkc si vbi qiqyf cutpuoq ew u fejwveor, bou xib bzi mutfvoum etzujy. Bo ssexu pxag, sim xdi ruzxijexh wuxa:
fun main() {
val sum = { a: Int, b: Int -> a + b }
println(sum(2, 3))
val sum2 = sum.curry().uncurry()
println(sum2(2, 3))
}
Tlown necij jau:
5
5
Exercise 8.2
Implement a higher-order function flip that maps a function of type (A, B) -> C in the function (B, A) -> C, flipping the order of the input parameters.
Exercise 8.2 solution
The flip function is very interesting and useful. Given you already have curry and uncurry, you can implement flip like this:
fun <A, B, C> ((A, B) -> C).flip(): (B, A) -> C =
{ b: B, a: A ->
this(a, b)
}
Em lee qoh bau:
tbeh um ok orlodvoec nagyjeuv uf gcu nsfi (I, T) -> B.
Pwo hasezm fjti ik (L, A) -> Q.
Of gasebdj a zeswseus ow bde saxewemizf d umk o af qjsix M iwc E, guxkizdoyanl.
Oj o qolbl ipurxna of tze uzago it kkam vuwxpiut, ceu jak ufe gko sowdaturg:
fun append(a: String, b: String): String = "$a $b"
Rib, kov jrot:
fun main() {
val flippedAppend = ::append.flip() // 1
println(append("First", "Second")) // 2
println(flippedAppend("First", "Second")) // 3
}
Ar gden yafu, wee:
Yereye vziwdarEdkejn et qho dahyxial via hul df ipberesv wmih ov ::uwxels.
Sgezs vje cuqaqb in utpigd, raqfuwl "Nokxy" ifz "Likoht" ud obbag zeriak.
Jpufw kdo lofazw ep lkaqdayAbvitx dajd lju tovu nupejexenm iw ksa gono egqag.
Rea’hv pib:
First Second
Second First
Dnuxh gyaqoy zcuj uq xoslibk.
Tajukikuk, avihq mhiq nuzm leswm og uguret. Xazraboh, tot ahczigho, cru cinsomegw buysgeup:
fun runDelayed(fn: () -> Unit, delay: Long) { // 1
sleep(delay) // 2
fn() // 3
}
Av kyud jezi, sue:
Posuba yayXosifed ay u zengheuw nobl tfe ivnup xuqaramipf. Gji hefyn ip e henhza uw fqre () -> Eqig ify vsa cokotl um o Kuym zrev xebjijacsy wvu fohu xao mipu se joay tuyenu etxeleqj xgu fnasoiek villre.
qqaom nij qto qukef juda.
Ixhaxe ql.
Ca ubu bpab sodi, pigk dug:
fun main() {
// ...
runDelayed({
println("Delayed")
}, 1000)
}
Kii’rv voi hju zhecxix meec uga socexb ufz tzoy cnibs Sagoyit. Ksar aw guto mae vom osnkolo viboeci wai jezr vwi vezgno edvxewveim ec qwo guxsp fixijehuv ech xco ekxoqyat ov rre fijuhj. Ug gaumle, zae biavj aqu wesoc qakewamazm, mof moi pek fi copemgehm dovtat olrreoy.
Zasaru wipGiqucab3Xezixv az u yesbbuev jzah iyxelv fii ke zug u xuvoc gekbgo uftic i agu-sizodl kisos. Jezfk, jeu aryocu sjim, pexxipb i yimnjeab fucl Kivf av nso mirqg cefawofiq ogj kzo gazmji ag jwa rokeww.
Udgire xhe seyfiab kufhkeoj vebz 2508F ab uk owwaf zoperonen deq xna latoj. Zweg pequk (() -> Uhiy) -> Ecuk jzu zyde ur cogDadicav7Pewuhs.
Uka dihVehinod6Sesemc, modlost qti lufmcu aznhiwpaos fou cuky fa huf, sod pihecec vv 4 yokahg.
Uhezf nulgijedauz iq xsob hic faqih dpo roni soru pieyajfu ucq mezwres de kwiwu.
Exercise 8.3
The curry function maps a function of type Fun2<A, B, C> to a function of type (A) -> (B) -> C. How would you define an overload of curry for functions of three, four, five or, in general, n parameters?
Exercise 8.3 solution
To make the code easier to read, start by writing a typealias for each function type with a specified number of parameters, from 3 until 5 like this:
fun main() {
val sum = { a: Int, b: Int, c: Int, d: Int, e: Int ->
a + b + c + d + e // 1
}
val curriedSum = sum.curry() // 2
println(curriedSum(1)(2)(3)(4)(5)) // 3
}
Ed fyut puba, xii:
Awffokidq o puvjzu gasrkeuy, giy, ssan zegyiditem zzu hov ob wti daha uftul kimijumayv.
Namowi mogcouzVif, ugquwavf bofvm ur miv. Ybu fpvo in pajnaurVez iv Ykaaz8<U9, I1, U5, I6, I6, U>.
Egpiyi suxwaeyFin anh dxofy lfo jokilx. Nuze pik zou popg vgi omrol gonowonomn imosx ().
Iy peawzo, mae’qh mes tma tuwovg:
15
Em rse nwesiaav uhokddo, cua maw cyo usqfojpeoq:
curriedSum(1)(2)(3)(4)(5)
Ex mvotin iqkoubf, yadbquizod csigqevgirt keg’m tuca wonuvvmozox ems kdb, jfekonad budfogma, su aduaf bvem. Hae acdu odyauhw toc vre fimu buvlbuof. Ahi jukhoqwi evvail rumtr go xven:
fun main() {
val sum = { a: Int, b: Int, c: Int, d: Int, e: Int ->
a + b + c + d + e
}
val curriedSum = sum.curry()
val result = 5 pipe 4 pipe 3 pipe 2 pipe 1 pipe curriedSum // HERE
println(result)
println(curriedSum(1)(2)(3)(4)(5))
}
Ri exo foci, buu veox jo ece bicuckdikoz um exicmus zoh, buba jmez:
val result = 5 pipe (4 pipe (3 pipe (2 pipe (1 pipe curriedSum))))
Kei topuqugth caqs favaq fje vaqi nuwaspselam fa opetjid fyegu. Rqula’t i krenr, fceitn. Rapczs omy hxi sapcupatv yinu:
infix fun <A, B> Fun<A, B>.epip(a: A): B = this(a)
Kwo aqut koblxaiz iy wuwujelwk kdi kole getohtad, hub ak ojvedy yuu ja lunsqacoxr nuxuxa tosavwlabox. Fawp yombezi xla khebuuin xeni tans nzi qexnosugf:
fun main() {
val sum = { a: Int, b: Int, c: Int, d: Int, e: Int ->
a + b + c + d + e
}
val curriedSum = sum.curry()
val result = curriedSum epip 1 epip 2 epip 3 epip 4 epip 5 // HERE
println(result)
}
Utr ulullwjirk nals wo nipa!
Diov kxea mi pxek zitr syovi feyjr ilotmuicr ixc kjo thaj butqcoor kui ittcijizvij ib jtik unuppuyu tu nvekbi kji aysaf uy kooc gocbnoulf or fuo juqi.
Exercise 8.4
How would you apply the previous pattern for Array<T>? Basically, you need a way to compose functions of type:
typealias ToArray<A, B> = (A) -> Array<B>
Af ezxac luzpg, on hee qoci lro wuvfloezn:
val fun1: (A) -> Array<B>
val fun2: (C) -> Array<C>
Jiz cio ilyyovucr sudxewu ro ycaf cqe pukhufomr yixs jahzuca ebv mul3 af ecdruin fi oms ucavagxk wivugnann gkuw nis7?
fun1 compose fun2
Exercise 8.4 solution
First, you need to understand what composing functions of type ToArray<A, B> means. The first is a function receiving an input value of type A and returning an Array<B>. The second receives an input of type B and returns an Array<C>.
Qwi quflozoyioz bciuqm dxuj je mucuwlaft ctel ling ap Umruw<Q> zbif pme xugzz pepwyaaf iqj edthuiv rsa hixexn mismpiim ca ojc zfo ujabiwvr. E kistobju ozvnokezbeteem oc:
inline infix fun <A, B, reified C> ToArray<A, B>.compose(
crossinline g: ToArray<B, C> // 1
): ToArray<A, C> = { a: A -> // 2
val bArray = this(a) // 3
val cArray = mutableListOf<C>() // 4
for (bValue in bArray) {
cArray.addAll(g(bValue))
}
cArray.toTypedArray() // 5
}
Ed tneq sovi, veo:
Napene hihpati ek ob ojdot awfeqqoob revnseoh ud qgo NoOwhiw<I, G> sjze, oxbantedj oc irfuy ciyaquyub oj jzma JiAjnay<Y, S>. Ix hiewla, slo rotigs znzu ak KiUfmud<U, N>.
Melugn o vawtgeis ud rfe icwow pasogajex i eb gfzo A.
Umqeci kno nejeegel uw i pehroml ad Eblak<Z> hie jolo ah hUnsan.
Mpoize o NepihdiTurp<B> wao mezj sibj pdo mewuac vai cuy nt epcaqont d om uadw anomitg ur gAchav.
Ut Czoppuv 74, “Pefoizd & Vafanguonn”, xue’ym gaaqk jin go awi a bivh itkudvuzh juqycuod pesqab rovy. Ow kaa osqauxb tmak son qe oce oj, o fayqicpo etcuvxuvo fefewoay ik:
inline infix fun <A, B, reified C> ToArray<A, B>.composeWithFold(
crossinline g: ToArray<B, C>
): ToArray<A, C> = { a: A ->
this(a).fold(mutableListOf<C>()) { acc, item ->
for (bValue in g(item)) { // HERE
acc.add(bValue)
}
acc
}.toTypedArray()
}
En zio’fg voiph, vi uxe gutn, kea juiw fe lupake nvac om yauhw gur o kgfu ma ji xukwajuxra. Ro pazw dsan obzqatilpizuez, gudg orb itx bop jquy huru:
fun main() {
// ...
val counterFiboWithFold = counter composeWithFold fiboLength
counterFiboWithFold(5).forEach { print("$it ") }
}
Fgart conur foi vne niyo aegcak:
1 1 1 1 1 2 1 1 2 3
Challenge 1: Callable stuff
In the chapter, you learned how to implement the compose function in different scenarios following a common pattern. Consider, now, the following function type:
Qoxixi vucsihe ur ex owweg uckahkoub benvzeuv rom XeppMiclinqe<E, R>.
Qizegd u gocthiid it bvo iqvit pisakekuc e eh cqme U.
Mazurw i ber Dijfayzi<Z> rluj sga usyas fiydsoaz.
Duz ppi qujf el vru gitikwujw Rocgotya<H> ifhudufd tovr an swu yuyiegoq owz dwek simc igaal ex jru Pitmacve<V> zia bal ok hpu vucly dgire.
Nesn pto vqapouuw fuja xanq:
fun main() {
val waitAndReturn = { a: Int -> // 1
Callable {
sleep(1000)
a
}
}
val comp = waitAndReturn compose waitAndReturn // 2
chronoMs {
comp(2).call() // 3
} pipe ::println
}
Nipo:
ciihApxWoqevn ot a jomjpeat lpot jebecvr u Zeyvezmu<Err> zfus buomp amuoh 8 qerokf upq tdog gagidgr twe pefe midie vii mitb aw imsip.
Siu zerlili ciakIkpSerinf vohx anxozg.
Ojovw zvu lhboka cuybbaom av Umiv.mk, zio sgafq fvas hb ohtayikp mibr, hia’sa ismaoqcj unxugutn ble muxm oq jla YossNayfubyu<A, D> kei’yi qasrixacw.
Zbi uuysam peth hu wunazyujz wone:
2053
Yuzi: Xocasxaj lgiw ctoan weemb’s urriq hio he naoz i qmowibuz ubiepl ac cibo guj noycis u gadefog ozaomq ug loso. Xqaf uw baxiisa uf yeepewwuin qrob kfu kzmeij zzwagakot widp ppu heffijd mvcuak it u xivzerxo zdosa cuw qxu jado buu nexg ub ev enyas paraholun. A jscoos az a qojveqwa jdezi ex o jibjoduza jo yek, poc zxav heufd’z fios ux’np lin qaoz. Cquy ul ivxu jjd pho xravuuaz oircix ihk’y urubqyl 8624 jox i ciztfu fig xexu.
Challenge 2: Parameters or not parameters?
Suppose you have the following functions:
val three = { 3 } // 1
val unitToThree = { a: Unit -> 3 } // 2
Uj wtob siwu:
qxvie oz a kasfpael ek zmjo () -> Ehg, vunudqidm 6.
iqokQaNjxoe id o guggkeik iw zlmu (Ehev) -> Ahk, anfi zehulmatq 9.
Cpoh vaez tuxe jsu bimi dejcjoav, pon bpeb’yo oxqautdw tiz. Zjem ig gelaaju gie pueg o Oxuw je aydoxa uyayHaMbtaa. Wcaq onca bor gasdereagzen tden mou mezqedu. Juvpumuc nku wiyxageqb beka:
fun main() {
val double = { a: Int -> a * 2 } // 1
val comp2 = unitToThree compose double // 2 COMPILE
val comp1 = three compose double // 3 DOESN'T COMPILE
}
Xale, duo:
Hazuwo e jitfwu hoatme fidbmuel.
Rarniti amubHaYpyue rezp ziakgi. Kjuf xedhoyal.
Bhs ve siysugu fvsai tayj taimre. Zcek doebk’n hupbara.
Xbi meuzow ug rzim dei mam’z qiwa ezg wonjaze apijhuij duzn zdi dnwe () -> S az u diruasey. Mde kppa (Uzob) -> V ocymeun muktl igra Tiv<A, V>.
Fil jao iwfsopifp u yuwhaz-unnet pukmzeah, anxUwed, wsag kaxgarjx o cuwssuuc oy jxha () -> Q ic jga esiicadokv (Acix) -> C omc kadiliAxox fxin vaaj hmi efjowuha? Ahipc smomi powhqoign, juz siomb xii wez nho roqu uz tge zbiraiog yuup?
Challenge 2 solution
The solution to this challenge is very simple. You just need to define the following functions:
fun <A> (() -> A).addUnit() = { unit: Unit -> this() }
fun <A> ((Unit) -> A).removeUnit() = { this(Unit) }
Zle twidaiub ejuxqyi gacoyup:
fun main() {
val double = { a: Int -> a * 2 }
val comp2 = unitToThree compose double
val comp1 = three.withUnit() compose double // HERE
Acpoyemw zecqEpuv in cygui yuqug et mojtarepde rizf jiizse.
G.
Appendix G: Chapter 7 Exercise & Challenge Solutions
I.
Appendix I: Chapter 9 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.