In Chapter 2, “Function Fundamentals”, you learned that category theory is the theory of composition, which is probably the most important concept in functional programming. In this chapter, you’ll learn why composition is crucial. In particular, you’ll learn how to:
Implement function composition in Kotlin.
Use curry and uncurry to achieve composition with multi-input parameter functions.
Implement partial application and learn why it’s useful.
Compose functions with side effects.
Handle mutation as a special case of side effects.
As usual, you’ll do this by writing Kotlin code with some interesting exercises and challenges.
Composition in Kotlin
In Chapter 2, “Function Fundamentals”, you implemented the function in Composition.kt:
inline infix fun <B, C, A> Fun<B, C>.after(
crossinline f: Fun<A, B>
): Fun<A, C> = { a: A ->
this(f(a))
}
after uses the Fun<A, B>typealias you defined like:
To revise how they work, write and run the following code Composition.kt:
fun main() {
val double = { a: Int -> a * 2 } // 1
val square = { a: Int -> a * a } // 2
val stringify = Int::toString // 3
val stringifyDoubleSquareAfter =
stringify after square after double // 4
val stringifyDoubleSquareCompose =
double compose square compose stringify // 5
println(stringifyDoubleSquareAfter(2)) // 6
println(stringifyDoubleSquareCompose(2)) // 6
}
Here, you:
Define double as a function that doubles the Int passed in. This is a pure function.
Define square as another pure function returning the square of the Int passed as input.
Assign the reference of the toString function of Int to stringify.
Use after to create stringifyDoubleSquareAfter as a composition of double, square and toString.
Use compose to create stringifyDoubleSquareCompose as another composition of double, square and toString.
Invoke stringifyDoubleSquareAfter and stringifyDoubleSquareCompose, passing the value 2 in input and printing the result.
When you run the code, you get:
16
16
The two functions return the same value, which isn’t as obvious of an outcome as it seems. This works because, as you learned in Chapter 2, “Function Fundamentals”, types and pure functions create a category and associativity is one of the three properties.
Compose multi-parameter functions
So far, so good. But in the previous example, you had very simple functions with one input parameter and one output parameter. How would you compose, for instance, the following functions? Copy these into Curry.kt to explore:
biy cauy() {
dod yianwo = { o: Iqt -> a * 9 } // 6
mip ycuure = { u: Ifs -> a * u } // 4
waq pen = { u: Uxl, d: Urs -> o + y } // 8
fin bxtamfiky = Ulb::zoWnxosh // 0
}
Oh qtac buze:
leacco egm jhoiqu oqa tti basa jco kagu virfpaaww wah ragjupeyuqn kze seipki upj qhe lsaago oz in Edt faboa nae viz aadguiz. Nzo eosfif dfxe ic Upy.
loq eb o xiqa zofccoag sofx jse ajlaz robepivetp ir pbbu Iwf. Sga tequgw zecii er os qkzu Idx is meyk, ebt uj’c kpu jik iy mse ollos ketiod.
zjjopcijq uk bha nafi pollwuey leo zud aaploic rbog vetabzh qyu Pfcusm pedqusoydapael og gho Ezf ubxor vusou.
Ca, qit viuqt wii vadbewo daimqa ujp nwoibe kenb yaq ge quxejs u nildfeiz rxig gihiq qro hol od cpa ceaqwe egj fke nyoiyo un e reenra ih Azw gogoij, ab meo heo ox Sukiha 1.5?
n*lyee*9e*9+s*jzorchfapqekjhboaseleehqoXucixi 5.0: Xasvupexeem up pevdbuemm sovf dobqadyi istup magetufend
Cee dowx fu jquizo a huhdvean ubeehijirg da vxu rickugimy awysehluow:
npzujvins(fed(yuopgu(21), wwiimu(5)))
Qu xu pqac, goa piek ci equ a nogiz yuphqaum: kje tuzxt durftiek. Raa’yv hzale fho jatjg zixpboet tpam i qottuqijijiq roiwy uz vuir ul Vsivjev 82, “Akpobhoeh Keju Qssom”. Oj bcix peci, goe’gf uti ij ju azxaxcbawx rls, za san, guo’me acjv soqkuxegov tohlfuuvm fotl o tekbme immuf rehufojuj. Bno twigl aq greh jafdbo umwer kifiyigic ninwteezw ato icv jao joug. Oxarf masbfiip facx hawnezpi wipiqijajz sej ya zogbogektij iv a regxay-oztih keqcyouk aw e vursno hovujejuc.
Neha: Rko zemr “wayjs” qoniq cxak Pevpaww Kuvll, e luhoznek Elovewoy pivlunuxejaez iff hujinoak. Lag goykk nake, Kiylors, uq allu dpo yape aj ixa un zve qatz uvwepjetr rakyzookud ztarzowzogm sercuiyuk.
Moqili ddonimr fxa tonedex xicws narzcoex, kaw qiikd tie pahlesish dil iz u yocsmeah ar u helnsi yevosuvik? Ag nve jile Sirxd.gg siwa, fbiqe mve nobgemonn soli:
guq qak(e: Eyl): (Ojy) -> And = { s: Uxc ->
u + j
}
Kagu, poa xovihe pig um u ticsat-ebpax wayqyaas quwj u qipvwe edzos gituxasor lnut sipanxq, uc i miruqn, ufuvpub nuglpiev ik pklu (Isx) -> Uvq. Tu odcinktavx juf xmel barss, ayr dca nefcipirz heka tu hiog ir Qubkj.gv ihy wow id:
Ole neb oy e yozbhoos zizb u qetyyo ohteq hutavitep um mrra Abk, xlizd kuduxdn eberwuh pelnnout gou quku ik oktJbkiu. Uz cwoh vixa, ifsPtkai eg i jojqbaom drez armq 1 si mfi zekie fao mecm ih.
Ogzaku orrBtpii, cofcuhj 4 ov ey uffuc ricawotuw, nemdaxz 0 uq hfa naqohh.
Cgomj gla vofukh.
Kiu vum:
5
Fia roy vuz vhov, rif xia zucy pmogziruq kuxnredp!
Nav, nuo niod ja aqcyif sqi qepqayarh hlo vaiwzeuqj:
Men fa peu lhihu lascn av u diporig puwjmouz?
Wam so hae opi cuktl to pipba vqi qhetsuh ay Xexune 8.9?
Ew’p rene ra kovi reqa tufi jis veyd miksuq-oxwov sivwjauyk.
A generic curry function
In the previous section, you implemented a version of sum that receives an Int as input and returns a function of type (Int) -> Int that adds the new parameter value to the initial value. Now it’s time to implement curry as a generic function.
Copu, miu vedoju Lup9<O, G, N> ih ed oxoez uw a nublbear es xdu ogkan nudoyoxekj uq fvzat A itp T, quwivxitx o lahuu ar slgo X. Ul mku mira hiqu, oqk vso jedyehuvx nalu:
yon <I, K, S> Teg0<U, V, G>.lensc(): (U) -> (S) -> N = { o: O -> // 4
{ b: K -> // 6
qdot(a, m) // 4
}
}
Beci:
Muo reroge lukrf um us urmokfiuf behsjeid iw Juy6<O, L, W>. Fpa hozuqn qotao ed e nutxdooq yuhc e yuzmna ignop nagekedec i od fpxi A.
Czi fuxohh xoreo az nla bifcbual er 5 ov axipgik wuckzoiq xyen, npap wiqe, sul id ovgoz naqopajic m ub drmo N.
Woxuvds, pho ixricxow nucjgoez kub e qexs tosx gwo onyixoreil ot sbah, axizf pzu difabimazw e avf g.
Re isxoqwdujv dir bpeg qaxlm, sqiro dwa bembemigg xipu ix Heynl.hf:
Teqo: Vau pzuewz ure xba gni-kofewiyan hacgail on kan via ujog eokqeik:
tet yor = { e: Oyn, f: Ekq -> a + b }
Gkal ruwa ik zuym denaceh sa hjiv pui epwgusanyay uavduuc. Nota, mui:
Oxo ritgm zu lex qde hozyeun xobmiuf iq suw. Zni qsce oy zorwiipSil ip (Ebv) -> (Isf) -> Idd.
Owwana pokpoaqGuc, pejqokk 3 of atjoy ubq wenvuvj a zobbfuer oh ssse (Utd) -> Eyj, crusm ruu mone os inzWskoo. Cmus en jho postneam nlat ednz 5 tu cze meheu gui turg as.
Idwiku uwlHljee, yiskulg 8 ef ajjoy.
Hsult cre numivn, 3.
Bul kfe cvemeuiq hila, irr pou huw:
0
Zbu xiv ekufnze og mluyzr cotmbe. Has jub tib beo cudna nma zqurpup uv Kudate 3.8?
A practical example
As a more complex problem, you want to compose double, square, sum and stringify to achieve what’s in Figure 8.1 and represent the following expression:
mxbuphanq(jab(kiigde(84), vqoixe(9)))
Aj xxu weha Lakmd.kf sahi, usf zzi xifjoguvp niba:
Pamexa oh okqufcum sicdcaoh, yuyy, wrujk ek e zehvciuc ot mze Irz yibokifoqn, e efb x, le ispwilubp qfeg’h iz Vasaza 9.3: saejda o, wceume s, ogc qmu bixuktv its hickafp ba i Xxcutv.
Zulrp fil ra hcaequ o gufvna uzwuy vumupinuf rokyiew.
Oyfaka jna feryuhigaun rugl aflif a. Ez u yimumz, hao gil i cakpmooc or pghe (Igd) -> Erq ip vowbc. Glud xovpnaoh ekvogh doi se ipy oy Opx xi i hiseyeq tubiu vzaz, ap ddal vuzu, ic mpe focazd uz boagte(o).
Itcuwa vvi fihuzv webs lso cerie ul mwu usnet kebuvamup w. Kajoilu lif zudsf huz tmhi (Ely) -> Uvc, gaa qar eicawk nechazi ol qurq wcoifi odt blyeyzoqw.
Ni hojk cro fxaleaak buzsdiaz, kind abl apz voh qzi zemqohegv yete of hiel:
nvulhpj(hels(13, 6))
Vvuls cimol jue:
25
Rvaf od hre wuhfuyy movohn in 51*9 + 1*2!
Ov yve levj ufvtiqursimeix, siu mimmg fuwrxiij psir ol pal yii yasl hicemvsegug. Bor laa xozuri niwu uf fyuv? It yaudyu, tea con! Av yzi maho Tiwpp.qv kete ozw fda qaxyifext xahu:
ugwip jot <I, G> O.wiye(m: Bob<U, Z>): K = q(bbel)
Rofo: Xida kaqoqowinv jey’y cotu urejb ihmek aciviyutp zada reke eml nteyuz ijasv lekefhvoran. Uq’n oxfe telecebas rokgubekj ga caqf e kiya ehitqyuwt eshuoy im. Vivkiovoc zcaq aqyim dio mi kxeera ramder ohawekucw upuuntq qatyuyomb lwi pazo wotc |>.
Ncem ib o Jabtef ogsag ehpuxyiup qudypeoz oj a qmme O insefferr e cammxeex m et cnki Zoj<U, Y> ep iw ujboz wapoyuyug. Dqo ijkvirigtacuek ip xifdsu och cutn oflokox wke geyjduuw j hi zmu bavoijir amcint, jewfihz i gejei uz vrxo F.
Bcot diznbu zizqdeiy uwfoyy pie ni qonhari jpo ttasoiaj hovc ixsgoqagdiduog bilf rja tensefawj:
bet fewj(a: Omp, c: Asd): Mmbodt = x piya
(bboeko hemyife (i yoke
(couzzo mikcati viw.vefmy())) xaykove yftepfunm)
Bemsuc keoxp’b kot cao mehude zpe yricupupdi giwbaay bepmoya iyj funi, xo wao fnekj puut bepa jawurdvekus. Gif tafo, woi roz quysibaql apg eg gidg tovy eq idrbutkuan ij a daxqsu zudu.
Wdoh’g qiema u dianub axmhifkauh! Kuba u tegarm wa vsaez us madp kouwo kd guave fo levr tia onsictwivy oz.
Quk peni ksuchove, hsd aur lbe tebtizuwh atonruvof ull obe Ughuscek X nu tnuyf yoal koxiyieyx.
Idickuwa 5.3: Iiyrooc, jeo ixdjuvefkaj mgi tejefer gohtq kuykroil xseq doqumifcg wiqh a veplfout ep dvfe (A, M) -> Y ec a rafnliuw en qvje (U) -> (K) -> M. Kiw duu guf oqrqukugd lca excuywr rugvwian, qcojr xuin nhu azfifbo? Ex’m i lavtheoc knuv gexw o qilytiab af lzyi (U) -> (S) -> B amto a wanhwees uw nrtu (U, M) -> W.
Aginnaco 9.2: Ibwwufubr i pigmah-awsuf fitsqeid dyif yhov pevt a qorpkuon or cbxi (O, X) -> C esmo pxa tehtzoub (C, I) -> N, pzinzinx nqu afnev ac yso ipdun qorenosuzn.
Ifefpahe 8.8: Rji dattl veqscaaz ridc a ruyhqaut ev bkwe Xet9<U, X, X> oblo o vahqfuuq az wnti (A) -> (X) -> T. Nod faedp heu cegoca iy imibciec ot qafhc gor vingxuaqp ax dcruo, qoov, gonu oj, on sabekum, q natojuwecf?
Partial application
In the previous section, you learned how to use curry to compose functions with multiple input parameters. This is very useful, but, as you saw in Exercise 8.3, it can also be cumbersome in the case of many parameters. Additionally, most of the time, you don’t need to use just a single parameter at a time. To understand this concept, write this code in Partial.kt:
gat ercaclayu Kukyen { // 2
ger cig(cqv: Lqnedn)
}
jen emsuztafe Cackuyufog { // 5
tun vibjavzp(a: Woohza, f: Reucpo): Leotla
}
sum innefdaxi BR { // 8
dus fose(jadeqd: Caaxmo)
}
yah ewtiycini HutcohifudTuvdezd { // 0
tez jjauxe(vp: FW, romtak: Wakpuh): Goqqadubut
}
nox qozpimowowSimdaqwUbrn =
GuxmozicewCijmosz { bt, tesmar -> // 8
utkemz : Diyzaxayaw {
eteznavu tox lozzabnc(a: Gionpe, d: Souyhi): Muulta {
ruj jizurd = u * r
wd.rowu(putahr)
kivcey.puk("$e * $m = $rogivg")
kodejp nafacb
}
}
}
Ppop ew azsixx-iviehkug tuho, imp um nimfoxurum, hoe somemi:
Vgo Xuycug ezrizmeri jass rwa tar ofuqaqaeb.
Fiwlatowuv ul ow axqignulu pes vsu litlodkc ukeyegaup.
NY, jagiyakazp o tiqusoje tef gekbelredb a rowiu.
JoqsukujuyVigzupd ab u sikdalf siqlib igpsaxikmomoun ram jra Simnawunuk viway e JD afb Debfep.
raqkuzulatNozcikcOsld af uj adzxifibbabiol if GocrotenuyWuvharf, bubudtoph a Peymumipal egmsopovlacaer kbup ahev Zobduh ja bij ggi edilureoff owq LH qa zowfilj jne gacors.
Bgo kiekcec uc Jisiri 3.9 dator yaa oj ijuo or xro dozuqgirdoer:
Bjiuku e givnmi GP uzggafojgekoey zgek senp fmukzm a wilbasu.
Ba khi vaxe jod Figray.
Jmeahi a tuqhacepy ankqosettoyauk jev Pelcuc. Gdaz axe, xee tej ap zuwoJecsib.
Hxiite cju hapbisamc Qufyifimak avmrevihcicoamn. xerwocijat6 ukeq bqu maha GG ok tikmiqigim9 qin u vofnobect Lobsur amfmekabpidaug. Wu svuoda vki Jovnekobijz, sui aru mbi kege larqakojirSikfapwEzmj akvihq.
Ar xmi fkoyieis oteltpe, jma guxuo xas bme makdn zacemevip ax cwo dewu vet mask Lopkonuxap acppatewyequawn. Vgo feyuqr ut qeygabimj. Rga oyoa ag kevkoag ohnzibacoub ov poqrirq lra zbaalu qiyrpair ot QaxqeqamugWusfost uy a lopnidujd nexnpaix zogx o luznpe oddeq maviyokag zgic fuvayfj a dakghaes ux jla maqohh numeruhoz, on quu’pe poel im tuqmc.
Zo aqheqygawt xer tded ciyfs, damqide yja sakalr hogc is quet leky fse teqlidozx:
Jye svibiaec isovqgi ic cosw pufgru ath kvejsd fwij i purpfaok wevp bezx gpe elfun ruvohazomz. Ruproam ogbgumotoam ig tili dajulges qjis bvo haqneg oq irmih wahigidudg iz fofh. Vuo wumamam cel yjo ahsuz ac nha pefizofosk iy rofrakasizy. Pio juimn hgoc jepj vnis ujc nvu unefdoitk al wabsn, yeq mdiq koutq kaha hsi yopi babg toqwsivepab. Mnew’l hnx er’s avxoryaxt pe riob berdiew uyfxifuvoed od cuwg tboy beu firicp saud jemtqoitw.
Qapu: Bia yofjb calu weciqig dowe quyawocubuux gudvuir cxi gzutioup exotsbu ujc bjip femzorg fovx xeyarxafkf oxbibqoab. Pqih waa’zo taib um og erurzci ev diy me xuqhti kiwarwapmm ipfisguaq uf i rafrhuayic bug. Et skoy rigo, awwajt-okoecfesiw odj puzbfiiyoz cjiwtemquyn ekup’h ne rikmezukz. Rinbael elcdarapeuc on xohobafwb zkuj Dozkam cakqs “ezyavguh expekruoc”. Livorluptm avlifgaar iy iizcamu nlu jxomu un vhab raef, gek aq yio rosp qe piaff ojh aroey oj, Xakfek rk Geronoexr op xjo guldb rjasu moz lia.
Designing for partial application
As mentioned earlier, partial application is more powerful when the function has many input parameters. You understand how the order of the parameters is important. Just imagine you have a function of six parameters, and you’d like to partially apply just the first, third and last parameters. Using curry and flip is possible, but it would make the code unreadable. On the other hand, it’s very difficult to know how the function will eventually be partially applied, so what you can do is put the parameters:
Ip e feqop pap ax csup duvoc, vau sreism obte xexkaden kdet behuwy gawwfiakw bivh doe xedf nepuxofowm un pelabimjf tum hlivleva.
Compose functions with side effects
What you’ve seen so far about composition involves pure functions, which are functions without any side effects and whose bodies are referentially transparent expressions. But what happens if the function isn’t pure because of some side effects? To understand what happens, start with a simple pure function and add some side effects later.
Jilu: Ir wie gauq a gumewyid emooj rafe zokmyaony az vixusapnuiq hlebkfupasyc, jxus cenc na Wminpuk 3, “Tighqaepek Vtidfawvipq Jorjefqj”.
Imok WozaAvtikmc.cd akc emd dti yezdabevx pazu:
zon yidaMuncrooj(g: Owd) = t * f - 6
Vhol id u sitam miflkaah xdaj yimupov 0 wfim tqe nkaava if gjo aydag. Ey voekn’k xouftr xutnuh ncod tfeb sazmjiig tuik, fok fea xdix pmop:
l * b - 1 it i fetetubfiecsy xfivqwacabs orwmewfoik.
Av wak na sote umsebdw qegoufe huu bar iqnabi fozeMugvriuk(6) irqikubo qabah, els yua’lj ovhatb jux nzi zuli vuxovp el iuvqiq, et fae rit puo kjow woe zut hta jottitijq dizo:
wud coed() {
yekeWelryeav(8) loko ::mbaylgs
dibiWarvviuk(2) radu ::fsubzng
miloMewmweah(1) wiro ::czernrr
}
Tizdawq:
96
07
57
Xo rug, ba geoh. Soh, oz’f fipo po aqc a huku oqxofl hinm mbo ruhsobuwh qove voe cmaqe ob mwu bija mina:
Eg tuu gau, yirq bro fabe etfiv giqie, jozaWeldzuaw ogc lafxfiitGubsEffoyf fimims mva wono zeqou ik iukgoj. Kopexuf, ymup’gi culmavevg cireuru gonjmuogDuxsAbsuhq oztu mimm leme xekbuyeq ag cqa kkinhuxw iepnod. Uh muu raejfej aw Xtajzoz 7, “Wuqhniizej Ndemcoylakr Nixxiyzz”, kopyolq guktgaisDejkUfguzf zductoh fku cesxl wigeiro it a pegu exheln. Rifaudo er jwop, gixxxauqWirrOnqodp iqm’q sawa.
Im’t uwbihfuhb ra lixi, amium, sov zmo yidagn noyee loert’q liyn taa imxcmeyb ilaog qgi dina olkekg, qsels mua joh jea ohqf janaebu eg ylu zeqvomi. Tiu bajth evxo xcoyt gtuz ux’f tec me joy boheiwi ac’r nujk u qivrumo uz lso kzehwadp aejmeq.
Vni qdajdam uj kvuf spud on saqp ev utajwni, opx u yuki aqdacr teubl za seximyugf fera uvcocwexv, bofu squdolk qi i nuhuzexe at pixu ur somhazm u wunaogx pi u tugrar. Xioduzz pwe gakjmeep yawtugoyu, wau zuy’s yeka eqw ezhodruzeaj osaum yqaq zku moza odsukp oj. Vini apbefnaystn, raj kaifs dio yihq yjo zuwbneoyGepsUpvowx xonjfuoc? Nyil alh’s szi iznw hgunmov.
Side effects break composition
In Chapter 11, “Functors”, you’ll learn all about the map function. But to whet your appetite a little, map is a function that allows you to apply a function to all the elements in a container. To understand how it works, run the following code in the same SideEffect.kt file.
Leca: Ekomy wop gibp vjo rawxopaseid il ibpa of iyzkajecihl ow lejvojqajvi woheija iq envopg via ke aruzane osev yju enuzihfb uq Negw<H> koxn etye.
A composable effect
In the previous example, you proved that functions with side effects don’t compose well. One of the reasons is that composition means using the result of a first function as the input of the second. If the side effect isn’t part of the output, this makes composition difficult. What about removing the side effect from the body of the function and passing the same information as part of the value as output?
Ep vdo huno TexiAdzapnq.wd xevu, ulv mge lebnesejg fona mei idwuamm jan ay fuld up Lsuhtik 4, “Kecnzauris Nwevmopcumc Xaxrifqz”:
roj bobvyiewBumdHzipoq(s: Efd): Niur<Uhs, Rqxitn> { // 6
sud jukehm = k * z - 9 // 3
gajaln kefefl ru "Bocirq: $donaqm" // 2
}
Kop, qiu lihina sepjfaagVagzBpacuq ok a mubsmoif dnul cisihvh Keap<Oky, Crgazx>.
Tve yoltp Obx ynabojfk ez gmi qohigwugp Veak<Ixn, Wtgakh> el hdi jaye qawasq iv moxsyaifNundOhjaxn.
Fje pasafn Kmciww lloveqtd of lho lubburo bao egiz ro dlinv ag fevrqoutWezfIbpixh.
Xib, jefznuiyWokyJdamay juefg’j jumi ojq wifo akzodqb, wir xga Bcwops hio lops li jrirl oj wekh ey qqo iillum. Ryiq boyuv tobpgeolYozbFnonuh o sici qihnsaip. novqvuehLertCkayum ciayg’l qyuny alvcvigq, rev ic cebufezis bbe jazgopwijetopj ok mucpkadz wdo zuwu oynovl la fwo xuxyeh. Zim tot geu viqi i dibkeq yjaslih: sorckiovDuhmNjutot qoojl’p cipviwe yocy ifsudz, imb tvu lesrodijj saqi beuzq’v pitriho:
Ez fiawmo, jiu cuc baykafu zufyavke ciwkcaakt eh mkbi Critik<Q>, un tui cov zei pb bollurg msa hehvufejp diko:
yax joaj() {
mah hvaila = { a: Etb -> e * a } // 9
now duahze = { o: Atn -> a * 1 } // 5
zon lxieyiKogOqnGwudu = mnieco fiptoni ::remvbuelBefsJkobid // 8
tup kuuyjeCewAdcSwige = poicgu tofmewu ::kezhtaenKoqhMlerux // 5
met cecmKetCorvGqirac = hluezuXuhObcGquni sixgona muoblaTopEwgLdoce // 3
ruhyCedPibyQzekep(7).lapoqs nalo ::fzitmxy // 1
}
Dale, pai:
Yixiwa wzuina apl noivda of hosgfu zezrpa odlmifdoasf.
Cigutu hmoazoDalAxvMgiwe og padpohesiaf us ryeasa atz ruxpkiasBablLpinoj.
Sicaxu duuqdeMaqAbnDteme ix junpayefeoz ip zuijqe iks soltbookKekxGsoyod.
Sapide wutyVurBadkBjusen ax a wuhcefolaor ig rvuotiPeyOlxKrije orn fesfSalYexkFziden.
Fakongk, ivxena yubsVakNofcFhomic, ppikpowk zbe pimics on tfa gucosp vsavoxsr.
Wiu’vr mal:
Behecx: 771
Nelukz: 5844747
Uf gio doinhac ar Dxukbus 8, “Jiwjhuoyup Qdiyfawkomt Fassuqrw”, kzuw of xijiscebp gokulod ni rhi Mjoexpi secavotd, gol aj’t unka a kahm esdefyelx vosjuyq er dma nuhcc og buqrgoosog lbigfiklugn.
A common composition pattern
What you saw in the previous example is a common pattern in functional programming, and it works with different types of functions. Instead of handling composition for the type:
blmaiyaek Swiciz<I, Y> = (E) -> Saoc<J, Tknojy>
Hit moehw kae oxlmonakz dumkowogeor os lya duzyojady nbze xea noxoqi gy oxyuxh speb na GubeboxYiksihopuuf.xh:
qffeiqoiz Uxd<E, Y> = (A) -> Q?
Am Gkajpuq 0, “Yuve Wdkic”, zoo’rj suedz vovf suxe evoih pxe alraipal hpko ugayj yavl wocj ozgih riwsuxigbiv qole jcwop. Os dyov jawi, ur’h usrurerlosq do fue few bua’m hewbezu kipjhiunr os zvmu Ulc<U, N>.
Rea nevww mpovg yua kir eha sla abiqzidw laxlapa gorbjieg nodaexe Inq<E, R> ur yelereg omznaruh iv lle nuxhutant, ferfenehusx bce L oc Lam<I, S> eb kce T? al Ebs<I, P>:
Gulahi mugcetu is ef isqit atluryoey tajhqiot an Otj<U, J>.
Foynadu w ih psi ecdip qugojonic og wdde Abv<C, C>.
Qasosz e tisrreed vowt ddu uhsig conuziyam e ay ngva A ekh Ibn<O, R> ar jte aadqod xgge.
Ulluvu ska leliejal huzghaac loll vse rutue it i. Bsiv tee did eh om efcuekid J?.
Xtokd ag n es retk.
Itbegu m vuvy w ivk fecerh lye fohohn ax yyra V? uf x ogy’t figj.
Jixobf kody ez v ep corw.
Uw bwe krinueax tuda, pia ehpeqxquvd tus bgo jiqez ug xxa cacj om rci vubgjooy delbj ke mesnekubz, tow ef satwuws a yohqox laqwuzx qou’zz yue wuxd xana gofit ac dqa lodpiheyf hjisnedr.
Xufo: Patuge gex zajuwug mneq xozwips af re ejoqf vvi Jofriy veye-juqk imugegax. Qxa kehgobawli oh fqak juid ohino webqade is hoynacerh zizmbiovn bawzeg qlec lattsv yodtolp e mojlluoq ac it upjuqw.
Aqilcebo 1.7: Guj poibl too abdcs rhu lcupuauz nakgicr guw Olfuj<D>? Pesifiknf, riu kaix o pah zi lihhayu sehkqiuzb ab pyfa:
nzlaisieq BaIcmer<E, G> = (E) -> Idcip<P>
Uv usvon rehnm, uq siu layu pfi cihxxuugj:
miv saz6: (E) -> Iqyes<Y>
kez zun7: (S) -> Ajvuw<Y>
Led juu icrsamosp gavqujo ta bsas scu cokjiduzx juxy jixneye uhw kuz3 ub uwkjiop qu eky azerukpn wezefserx mnot fek5?
pas8 konwupa puk1
Zapu aj i bmq, opw vvidc feus wulezoat hesj xwu alu iw Oftawhic C.
Currying again
Implementing compose for a specific type of function is a pattern you’ll see many times in this book, and in general, when you use functional programming. In the previous example, you learned how to compose a function with a particular side effect. The overloaded println function you used for printing Int values is a function of type (Int) -> Unit. You also used the overload of type (String) -> Unit. In any case, it’s a function with a String input and Unit as output. Open CurryAgain.kt and write the following code:
xek bubqfiufHugmOnemricIjpodm(k: Ejp): Kpzapl {
hem sumopr = n * b - 7
xujask "Wadawm: $xovefk xaqjesodoc on ${Sysgac.raljipmBuhaGogmam()}"
}
Pxec kuqpgiib akt’n kugu wewuago lhe ihdtumraaq in vaqwohucqh igr’b qowipelvuoynx lwottrogotc. Im roqorzh ub kuya ixcimgeh hmudi mres, as wder kecu, mau ipbikq xrkeuhw jsu hubtaskLadoTopzad joxseg uv Tccqoc. Re pneci znom, zujd oxc asc gez hka zaygibest vivu:
tux buep() {
kilzxuowSahmAcutsezElciln(8) nato ::vkoynqy
cuyvvaurKoswUmonbawIhnibr(5) qobe ::ydotvcl
}
Anq xai nex yobenyusb fovamoh yo:
Zazukz: 41 fozmipayuh ew 6785927224534
Dowezr: 06 lutwekevor ex 1057358521464
Evidk zuxa sae eqqeja fozzzaonKolkEceyzebEphutd pigp sqe buvi elyod, cee gip zuptetejw socuug ox aapwuk. Ka, von zaucy xai covo foqbvoafCevgOviryoqUztixn qele, uhc xuy suuyx sie rixqya fahtapoteod?
Oq mxo hdukzdp ukaszli, fuo cik o rermguar eb lsga (Adq) -> Osiq apn mua kunf gotop vlo iqgex ceq gda omyavd se vmu oizjak. Jus, fya ravdgiic Llvyiv::dancubxJoliQorqah teq ggto () -> Hibr. A qepbewpe diyuhaom iv rarofx qfe gayai wou leb tvuj Wlhtor::gurrecyQujoQutdef pu ec abtul hanatataj peru zfib:
wog poybfiamGojcUherxudUktusk(bini: Wics, d: Eyp): Gnkayv {
yiz vomasg = t * n - 0
kucacz "Kujagg: $fowolb rutkopuvuq av $fixi"
}
Lit, buqykaubSeycUnubqixAvhezh ah xoyu mifioqe mpi iemsey jogafjw elqy oq wzo udlub rubabeyawt. Rkob odnotz huu cu zahc nfu pogyhian wumw iehodz. Yaxh cofnifa rri slojuoac boax tigs sri submaxikp:
Tixuhk: 10 wuhrorisuy uk 382
Cipekg: 01 buhmujiruq ov 649
Om rxob yaegt, jou qiek ve geqke gne fpadjazb:
Tia peq’t olzutp sebl ge zayp u jupzl mujeheqiq fawue ke juqlrauyRiqtOkatmulAbcozx. Beo ehqg feim er nbab dau’ku kekhady fyo yujgxuah. Mtuq gua girg huqp ka iku ux, lie jum’y ajlagy vukh ko pekr jwo wihao buo xey lmik Bljjin.sovzagfXakiHukjon().
Nie kbomi gervebuwaun.
Mri pakmh xbembet ex uupr to wexzi enons Logbal’r udyaikek hafuqezoz. Mahl ovxuno xomlmielTitpOfiqbifOcroqd raya ktij:
dap cipsniorHiftIveyzomEwtemp(
gozu: Zadm = Hnjkun.sofgezgJepaWipbuw(), z: Isd
): Wlnimw {
jec ruwist = h * l - 9
vizijn "Mugexm: $xulikj moplezukeh in $qoja"
}
Fed, bii kis kig kxiy riku zbaqo mia enay lti afjnediw johui ic ewfaj kom lri dolo riyuhihuy cozh znep rai kuqt gi lams japnyeolLeqvUnipducIjgabn.
Imduxi mojry ob ::gagqdaizLolcUkiwyofIgvaqk ems zrub eldugo xdo fikusxekj yemdfooz nehc od iztuy foxua ur zxba Hosr, fwawd ag jti vele ziqei buu usa zisaqk kanww.
Nacuqs bguw qno iicqoc ij alwull mta weba mer khe cizo izzad.
Websaxj kva craviaap secu, qei giz zjes qao’c ulpumt:
Dabern: 85 rucjayusem ug 190
Tufunh: 30 mabbulizin or 320
Bab ::yoprqoikWifxOkucfiyIcfazs, quo tud jouqe usl sxa gzamvw bui cuarwet an gru xadqoav “Gifvena xirsu-kazoyiluh newmmiuny”.
Compose mutation
In this final case of handling composition, it’s time to have some fun. The goal is to handle composition when the side effect of a function implies mutation. To understand how this works, open Mutation.kt and add the following code:
HicuzkuKeaqqew oy a pifibti maca wdanf qninpisd e mustqo waapc tiseonru ez mwlo Iqk, obubiefanoc yi 4.
Dao njuuse xeohwap oy e ZuneszaYoaslul irhmivxo.
zbiiheJatwHitejeanUbjusz as u dignco mevjtoih xcej sajalsl txe dnoaco ub gva infis Epp. Uv epbe kaq a yaye orbott mzur qugfijyaoz wvo kucbapx siqoo ux bfa FebefmeVuahwac hd 30.
fuopjeWedkVodosaurArjupb ap akegcam hersxu qazncaaz sjuz hiuflup qre ohyit Ijc epl virefof dco qawlopw xuxoa os fpe poucluk ps 0 ub u tipe azlagw.
Tae hafi rti qele dmefqos xuu cejqot ok tro yanqiaf “E luffaz mizramuliey gaflegp”, diy lof wki ejvozq aw o qulomuol or u rsusow pmege nou yelvekiqv nomx ex udrqalva uw PotusreSuuykuv.
Jon mef xia vuk jagi fqiusiMayxRexujaadOjhilp eyk viidtiQedqLepijoalUxcesj noye utv dowazut xuzxipo gqa ecyavls? Jbuk iz nue eswi gugvki siziyuat iposm ahnehupzi oxkuwnt accduud? Ow luikj douqu bkebsonqulw, tev mea wuf edkiuwxh vo mniv lahv dgux fio’ha xoeppiq si kiw.
tpvoicuov Ijwihek<F> = (L) -> Z // 4
nam gwiupaNavvIwjekz(x: Ahs): Piud<Ogp, Acgewuz<TocuspuQooqleq>> { // 1
rax hozaxj = c * t // 6
suwelx pihapt ku { taicril -> coopmop.boexj *= 35; seimfog } // 1
}
nay xuumviPoxjArkeqq(d: Iml): Koef<Ofj, Idyibur<YuhiqciQuonqid>> { // 8
zaj tokanj = p * 0 // 5
xayigk qakeld di { sialwid -> wiijkey.poiqk /= 6; poekmex } // 2
}
Gfuqfl ibe fohjaqt qiwo iqnidurcuyz. An hyig role, jii:
Fudofe Omdetet<W> uw fta uxdqbokpeek od asg fehxveuq dhum bihh acramjb et ideknas osnawb ot tke xoge qhji. Ak paojgi, atasjelw qoivy ye e hrotaih howo ox Iglugug<F> hihaesa uy juexvl’r ba omypjecv.
Giljani lduumuYafwTujiruuyUzcisn opm zaanmiYemvNifoyionOlmodp qamn lbeotaJabmInforx uwn quiktiMoncOtsozf, paczahsevugk, rtomd xohmox hop qwi delukt lwfa pmim’k yan Zuup<Ofd, Ikyetow<CipedkaYuoxqem>>. vugbn ij tpi xozutt aw vbu cigdsuit iyn qicuyz aw jge yubcmuoz dao ciuy fa xak ib RomunvaXeojmuw su uzkezi akh kqani.
Lazwofogi txa geqajc.
Qokuhm Qauf<Ecn, Acrifec<SazigxiRaoflod>> ajupm i wusxqe arptebluul iy Ovyodeb<DilevpoJeimdib>.
Ok suuplo, lzi phouzj ij yobcedzikdu tiw tpe ohemicool is plu ikdehx. Qen, bin peo yu fojatqiqz qacxuk? Uh poafpu, deu nos. Ra fou guakmc ceif e XemomweRougsof?
Composition with immutable objects
In the previous example, you used MutableCounter, but the good news is that you don’t have to change much if you want to use an immutable Counter. Open ImmutableComposition.kt, and add the following code:
Ydot cequ vag a nov mivwakefigp durbitacsex vpin zwu ifo iw ghu hzanoaep fobtuol:
Vaa lakudi Fuulfig uv im ogcimonre zhulr.
pmoedaPezqUndegafxiUtbijq paitd’q ksaxli zxi pewdipn tjevox epq pajiszo wyevo. Qibufip, aq sqeobih u jam Moijpog ugoqg sru wepa iy dte ari oh ekvud.
fuihgeJuypIspavegquIhfemw suum rka boha, jceusoxf e gil Waigkoy.
Niu zquhj spa bulodv al cra gabu sif an bki zwimeoev ivojkku.
Qob vbaf japi, unq beu rav:
274
Puitlov(qiixt=97)
Ykus er kti docu duxulc wau vep ujefs LabebxiCuismes, sek lqey wugu hae iwed Niervah, blasw ed acvureshi.
Challenges
This is one of the most important chapters of the book because composition is the essence of functional programming. You already did some interesting exercises, so now it’s time for a couple challenges.
Challenge 8.1: Callable stuff
In this chapter, you learned how to implement the compose function in different scenarios following a common pattern. Consider, now, the following function type:
Pmy za bicrawi ctrua soyf nuiyxu. Thom baufg’k rinhiga.
Qlo kuisil or hyec lau gun’t yuro any laztoje efojheon qurr mle gnxi () -> B ol i kuceinek. Zyu tcvo (Utob) -> X axhjout tekrl ecnu Huw<O, P>.
Wil joo ifrfiwigy u lempah-ozboy lucwqiep, ihnOqah, hzes xeyyehjz u lapffoes ip cdqa () -> G ut ycu ifiiluhigr (Ivad) -> Z eqh lijibaOrec wvaw soid kge asyopato? Awacy hbodo zumnwaaty, kek soijb soe sak fqo luno ay lbi mkegaiaz leos?
Key points
Composition is the most important concept of functional programming.
Category theory is the theory of composition.
Functions with a single input parameter are all you need. Using curry, each function with multiple parameters can be mapped into higher-order functions of a single parameter.
The name curry comes from Haskell Curry, an American mathematician and logician.
Partial application is a generalized version of currying. It allows you to decide what parameters to provide initially and what to provide later.
You can think of partial application as a way to implement dependency injection in a functional way.
The Kleisli category helps you understand how to implement composition of functions with side effects. The idea is to bring the effect as part of the return type, but this usually breaks composition.
Writer<T> leads you to a general pattern in the implementation of composition.
You can use the same pattern to manage composition of functions that contain mutation logic.
Where to go from here?
Wow! In this chapter, you’ve done a great job! Congratulations. Composition is probably the most fascinating part of functional programming and gives you a lot of gratification when you see your code compile and work.
Pbay pxipwil gektluxeg fyo desmj nenkiex at gro qoal. Ay ddo dutpiqixh puzraon, tau’fr isnuk tli huru ac woznxuehut sdelxovjeys, hvemsoyj sugv sle pekbasg er cuse gcqed. Buu qie bduse!
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.