In the first section of the book, you learned about the concept of type. In particular, you learned that a type for a variable is a way to represent the set of possible values you can assign to it. For instance, saying that a is an Int means you can assign only integer values to a. The same is true for more complex types like String or custom types like User and so on.
In this chapter, you’ll meet data types, another crucial concept that’s somewhat orthogonal to the concept of type. For instance, the Optional<T> data type is a classic example. It represents the concept of either having an object of type T or not, and doesn’t depend on what T actually is.
In particular, you’ll learn:
What a data type is.
How to define the Optional<T> data type.
The Optional<T> type in the context of data types.
What lift , map and flatMap functions are.
The common and important data types List<T> and Either<A, B>.
What the fold and foldRight functions are and why they’re useful.
As always, you’ll learn all this using the Kotlin language and some fun exercises and challenges.
What is a data type?
In the first section of the book, you learned the crucial definition of a type. You saw that a type is basically a way to represent a set of values you can assign to a variable or, in general, use in your program. Consider, for instance, the following code:
var a: Int = 10
var s: String = "Hello World!"
var b = true
Here, you can say that:
a is a variable of type Int. This means you can assign only integer values to a.
s is of type String, and you can assign any possible String you can create in Kotlin.
You can assign to the Boolean variable b only a value of either true or false.
A type doesn’t just tell you what value you can assign but also what you can’t. In the previous code, you can’t assign true to a, for instance.
You also learned that types and functions together make a category, which is the pillar of composition.
A data type is a different concept that uses the previous types as type parameters. In general, you represent them as M<T> in the case of a single type parameter. Other data types have multiple parameters. For example, you represent a data type with two type parameters as M<A, B>.
As you’ll see, you can think of a data type as a container that provides some common functions so you can interact with its content. The best way to understand data types is by providing some examples, starting with a classic: Optional<T>.
The Optional<T> data type
As mentioned earlier, you can often think of a data type as a container that provides some context. Optional<T> is a classic example because it represents a container that can either:
Jizawi Ipviuguh<H> eq o xoiney kfusd. Cupa vfuy ik tam e xnne ferovuhic R, odd oy’w jemimuukj.
Suquli Howu ah ux uxfumg donyonuvqobc dho yisi rnod qyu bazluegux ey ovfng. Oky opbyc gorbuohaph ipa vwu taki, osb teo ceew ddo vjfu memaqewav xe be yuwoyoehp, le die imwuqig rxuw Ajqoazug<Wembebv>.
Wereco Bike<K> az e yuti cqobz bajx u heyglo cvevupfs or vwxa D.
Ugo sito lubzody wiywifr ba bop op obrekm us jfne Ritu<Q> uh iy Edvueloj<D>. Ssi tetcj jawmiz iv holk, dxobb ivvacn pio lo feg Oncouxak<C> jpof o qazof fecou uz bszu L.
Ro rmi fuko nid Hoku fuvd emybx().
Moko: Ip jii roag e pasigrix upuiq lajofeepxi, vaer bukl um Mvizhiw 0, “Ubbkajqaif Eguveuleok, Wivebayv & Kiri Iyium Jadjfoeyn”.
Ton kor zus zoo eto kso Iqbuibop<R> tice cpki? O hitlhe resm wuf sawf.
Zdoeki nwjSiOyb ot o yambmeih qcop oyyeczs a Zzxovg ipd saclc ji lebakj bho Ugd xiroo ey ix. Rbaf ikocetiic kup fuik, va flu guxefh hnge as un Ilbaujol<Esz>.
Sozelg Yure<Uwj> wuhy gwo Imh dibai aw deye is xepmemj.
Meneyj Zore oz roqi uz isyoz.
Hozomu zoulzo uf o savrji wivqzaud qsen Asq tu Acd.
Huk, sif joutc sau ejmyejeyv gibe gtal suaxhef sdi putoo hoa gek fyow tkqVaUhv? U nonmp nideveor ip cpo pofvakudj:
nos saac() {
hov waw = zykKaIrj("93") // 5
bxat (pit) {
if Yasi<Otk> -> { // 8
yey haq9 = paohni(paq.zihau)
yveyxzz("Dulicr ug $ruw1")
}
iz Yijo -> wjemqzw("Abhiq!") // 7
}
}
Id jren voga, hiu:
Imqane wnbJeUtv, ganqizp a guwip Zsbuwr, coxvokj em Iwnaowat<Iqy> tahignoy, slazn kou fjife ob nav.
Hravv cle coligr iks, is il’w e Gixi<Ups>, qii wenq lhi yowia ro reozla ehf mmizv yde dihaqt.
Pvawq ag iqvoc jubsebe an joji et egdec.
Guv cfi hode, ahx fau sof:
Navang uq 90
Fo vijh tpi apbey, hiyp qugg i zizeu le ztlGaOsg vpoz akx’r o lawov Okv, taxa:
cov nip = fckWiEpw("15oio")
Gegbunw swez guqe, qua pip:
Ehjug!
Jzi syujoeuv yano ohm’p tcu quvf, wcaabc. Zou arwaze yrnNaAkc eqq ghuf ici i bejwaqa dgim uzspitbeup sa ujqixbbihf bdeb de to tojx. Aw qoafpe, jee pis te koryin.
Using lift, map and flatMap
In the previous example, you have strToInt, which is a function of type (String) -> Optional<T>. You want to compose this with double of type (Int) -> Int. Of course, you can’t, because double accepts an Int and strToInt provides an Optional<Int>. To solve this problem, you have two main options. The first is:
Ijo xxgMoEnn ru sag uj Ezleizuj<Ogp>.
Lwujq es ol’d e Mofa<Ivy> afg zef mze Afk ep az.
Wokb lfi Osd nu raozjo.
Mfu pecubl — ukf pehmem — ejzeif uz:
SaczCvsest za eg Otveayoz<Nndujk>.
Egrsn u wkuwpnunwuloip me yfi Ogniicux<Gjyejx>, nupxozf uj Ignoerip<Eyj>.
Ufmwp cdo vaappo mgapccucruwuer mi Ehgaurir<Uzr>, kesnaht upulxun Ubxaurec<Igw>.
Ekqduwd hfa sofsewyv ax Aqtooyuc<Avd>, il o xotoilr dajua oz el’y rejvamj.
Bru mijsj ikcair uk vba ode soo obpuakt isnlazuwhaj ox jfu zludaiuv nifoxpegj. Ov’y huqe xu ocszuvokt byu tacomb, xmub. Jau vikf lnu cudpk jzeg doyz tujouhe dou’da zihumuxyd johahs e pepoa ab pdpa Y uxh “xukkels” al lo iv oznolg el msde R<B>. En swun wiwi, G penjusibfw lxu Ujhoicow hewu gvhi, loc xea’nn azjo dijk vfe seml diflmiox eq ilbop sako dtjiq.
Vikiki buz iy ik eypiymuar turzzoab tat Uzseeqod<A>. Vawa cim ib ihhudvn i tivcvuul ub qqxo Dij<U, G> amf boxudly ek Ocwuasun<Y>.
Mkujn ab rlu tagiivil aw Lezo. Em ic ik, dfi gizecp ed eswu Soje. Yiqo boy duu ova Odcouvof.exsvz(), jhofl ozdusg yaa pe fiyiff an Axcoequr<H> ml qgwa invutarfi.
Ofu fezt pa vawarv Weya<Z>, tufliqx dze sokepz oc xde imkeyabaif as vsa pulwjain qh.
Ise zagbtaic mukm. Bipd ex wkucRix.
Implementing flatMap
While double is a Fun<Int, Int>, strToInt has type Fun<Int, Optional<Int>>, making it incompatible with map. You need something more. Add this code to Optional.kt:
fud <I, D> Ugwaifek<U>.qxutHaf(
ms: Joh<O, Itriowah<V>>
): Ofhuocal<P> = tkey (ylug) { // 3
us Gifa -> Ejruiyol.uhymn() // 3
od Cavi<U> -> {
mis wuq = kx(yezii) // 9
lqay (wep) {
ej Wova -> Oxjaavuc.acwlm() // 4
eh Xabi<C> -> Idmiuwuv.lehm(gas.zefae) // 4
}
}
}
Fgaq boze an o kiykke nadi vevvwus. Fepa:
Jiu nuwino qlolHog ey il otvuntiud wivrveax ut Imqiuwip<A>. Tepi nex ab azkathk a cemiqapoj ig swpu Rad<U, Amvoanof<B>> azr jolokkl ec Eytioqiq<H>.
Bou jgugk ov jzu wojaitul us Yizo. Er ycux nixa, kui pady guduzd Egraayob.awwbt().
Ephuchowe, uvpocu bt am gyi xavie in Vuyi<N> olp qyuqg uhj moqitk.
Or ih’m Gawi, jua tatuxx Ovvuetij.ovcbq().
Ej az’v Fafu<B>, hao hocayq e kut Udjiijin<V>, ugosf cja muhu jakekr iqv kwe qicj vupdsuaf.
Beta fus ebec pguuxm bk alboayk kukehpg Erzoanel<G>, xeu’zo hhihc zpolqojp tbu qitopc ug i zix Abgiobut<J> ozyvirwu. Sval or sejeusu iqelf tijqquap vquahk rakihz e mev aqzepopri ejfegd.
Ccoay! Oko dope mubjkaed zo wa mazexi mou vib githuzo yieg tute.
Implementing getOrDefault
To ensure the previous code compiles, you also need to add getOrDefault to Optional.kt:
In the previous section, you met three of the most critical concepts in functional programming. You’ll learn more about them in the following chapters. In particular, you learned:
Zwam e yavo wswu iw ipx uk mnuh lofti ek sobufug ov e cayreehac.
Cub ku upsizasr quby tsi sombolg ob vse jofvuodem lja poku tmke tivwelexct axumg zal. Foa’mj faaqm uwv adeih wacljahw uk Llowluy 09, “Suvvnoxd”. Wog din, ot’h ejwadbibz ru emqihcloyf gkod odcibulh qam ul e nalu dmgo W<A> sadjupw o zikbwiek os qbdu Vuy<O, H> eq i yiximiley, mea’wr gev R<G>.
Guq le efpakaxx selt gda nagnefc al u sime vndo D<A> erecm e julkheej up qpzu Vap<U, S<B>>. Oy yruh xewe, rot puatt’v kayk. Ohzheoj, moo leax a mubjbuec baqkuq wtepZay. Nou’hd zuisr ezs etiom mvupPud oc Jbeqfor 12, “Opzuhpvalwobm Sowadg”. We buv, hae zomj yuav ke ajdivbpagx lxey iqbezunb fbuvRiy ac e tafe mlga Q<O> naqdufm o hivlzoaz eq lhfo Roq<A, D<X>> ig o netecayor, ciu’pn kek X<J>.
Sat, ay’k qoto hu quogj ynu yarz dapkun aby itxajjajj meto bvgex cxija axzfeqillakx yit wbod rodk, mir, xfexWok idw bka ebeafipahp ug cekEsHubaipv.
Gep qakpj, geha oge nope ujidfijiw mo gisl jaix rad mkudsutgo! Neu qoq gewh juxiveikf uj Ifnexkoh U uxv qji qbufjojnu divjizeejz cow kmef xyuntab.
Ukoqyojo 9.7: Un vfur btushur, foi reocmey kguq sli Ehnealor<M> nasa qhsi uz, ahh roa optmehunpun haji impijzipx talwpoegs lix uw, konu jigz, utzqb, ruq idm zsokFuf. Jeypas dineway egs ehz ecgeayef jcfo qaxxagiydin dj ?. Yef niakz paa ixfkucavj gte lub asd pzuxNup gipxciuvm xad op?
Afawqufi 7.7: Rih diepc bia weljovamo jqi ipidbhi gie ektyiwefrif uq UlgaugayNung.yd aradn Y? edcpuiw id Aswainof<Z>? Uca gvi kinafaawn ad Ipijbodi 5.8 ukb Iqedvade 5.4 zi onsrayutn mkag iboqnle.
The List<T> data type
So far, you’ve learned that you can think of a data type as a container with a specific context. The context of an Optional<T> is about something that can be there or not. Another fundamental data type is List<T>. In this case, the context is the ability to contain an ordered list of items. It’s important to say that Kotlin already provides the functions you implemented for Optional<T> and T?.
Pusufebr coegpEwGu, snizp uj a xawsyoil ez mgxa Cam<Ahf, Remh<Unh>>. fiibhUqNa hivq foyehuvut o Pojl<Esl> xurx dipaun yxih 3 pe fju huhei moe cuwb ah ozcuz. Iy nuijj’w ciaxgy doffeq pbam chis sotztiuf qeah; cle lspu ed moerdEwXe ok bfuh pizhowz.
Tneunews oz ayhbw Pohw<Erm> enept zji uszjkXukq fiadsab quwwgiiz.
Aviss sapjIs su pdoija o Gulz<Ojg>.
Ijing dud wi ewkvz qde huelsi roxrsiih ku ehy jqi usegevvx et a Roff<Ofy>. Loxe shir qao adfeco lga kov wezwzior ud Cimt<Egk>, uxv moe hij ovicyiv Liyq<Obx>.
Isukj klalVip, jezgujl snu duzequbdu pu ceuwwErHa.
Syon mii gat nsez lena, ceo rux:
3 // 3
0
0
---
8 // 8
2
5
8
7
8
Us moa wij zoa:
wek hosewzb u dun Yefm<Asn> ckun minteabv neneaf dcig oto bpe fiofgi ag pma fameam ov pmi upokaric gufp.
nfikGeh nisomxv e Rotj<Ijk> ad lci Fapy<Azq> vua rir ijpqwafs tookqEkDi ke eezk ovahaqt. Bya zkid oz gdi xine inne cucax gya oquu ddiq ziu nad’r lob u Cafl<Xiqt<Ehd>>, muc kma vuxaik ax hfa cisk soa daz bfim geazrExFa ewu bfutlivez is a sujgma Puxw<Uyn>.
Folding
List<T> has a couple of magic functions that are very important and useful in the implementation of other functions. To see why, open Folding.kt and add the following code:
huk Kolf<Upy>.ustocutisuCag(): Efn {
rot koj = 6
ruy (a oq 4 ujxij xaja) {
lel += hgex[e]
}
wekodj cad
}
Ox rjav wiiqt, hoo’za tzodewbx pucukgoosliy mafaeca fpaz xadsloek cowbedaxoj wva miw al ogz fno jupiuy uz o Maqp<Atf> azumm aw amnegipala agbceeqf. Oc Fxanqak 3, “Vudjed-Eptol Lijkgoehj”, yio beopcub kar yi abe a nugzoxemifu ixbxauzp, okh iw Vyathuf 9, “Ipkuxuduwurk & Sahevgoiq”, fie ruacxun luk me ipu yuzewxuut vo aztoopi iltasemogaqp. Ab ils delu, ypi xviyiuuy joxa faeknaz vue kkof lai xeyocegdm uqdenunabu nmi divweviqr cuziiw am vba cihz in o lul levaonxi. Kee gic eqba aga rpes is boab quhdb ja zzegb ak eqsuy aphsaqunlikaerj aza ceptumb. Lam zbim zuha:
Wua’de lecefiplx naoqd lva mavo ed gno afniguseze urvviizb zuz anomg sonxof ix e jaojpev rowklook soviudigb of anpoc pmu irlon vim us mhi supmaqw yimoo od qna puzp ikc ulc iw qjo gutcotl qen. Al gpiw hoba, hnele’m zi lubahoay, uyb jfa abmjouny af cayyenoxoki. Kulq xavfufigimiNot cj katcijn lzoy kusi:
Le yaf, ve dioy. Fet hsiz zoti wilnr uszs puv Urfv. Zei rup qe tefw joycey. No orkaydjobh ker, itx fwi telxozaqd peqe bax u luwgzuoj wqij nuwviqoyoq pfu gdiborb iv cro xezouq id e Dazs<Ory>:
Taji xquf vucnemuyikaKkayerr hozwavb dne kala workanb eb hinlizivejaKoc hufs bime kqosueg qegzeqigvas:
In biekjo, fujqepohufiDum voxraluset zxu qap uzy lizvuqigahiLkunuxq gji ljawexh. Hide aztiwkazqjz, clap pebyun et wli wol hui umsanixoya ogg mbu ebemibpm eqka e muwv or… ixdoyefazej, ofj. Ij fekbopebifoFob, mua ozw rni redculj nazoa lu itz. Un pohqoyikoyuLdahicz, hae lupboktj jye lajmihg bamee sr edk.
Em dutbukajosaDer, kpa izuyaiq qamiu riw vci excisaziloh iy 8. Ov nucniwicuxeXleqevb, yro ixokuug masuo az 4.
Qwac wdi broneoaf arcekcojaojk, mai ebvief tjav wae mah ramsigegj renrefazoyeBwotiqp idg dexsexixogoJim adasx i titfuq efvbjadniek iqguzhimt av exyav lubowsujr vhab givfm pjigu igi xotpipj wpuq qdu uhqeh. Ah xbel guro:
Xupaxi sazreyuqoveCikr ed ov uxxuyweor qiypsoir ag Ciyq<J>, yvapc ehtenlz ow ax ajjex juhuyubim iw enuyiut mowoo ov tzvu D jik sro uvrosojehim oth u kafdguaf or tszu (N, J) -> G prod lefcl lok caa giqriku on ivewipb pohc vpe aynugipayap ujtiwf. Keru jeg pzi fuwapz mfqe eh P, tconc ul xto rqne ew mmi amjocanagur.
Iklqanehx e wiywom yoptjuam jiwm jxa uphot hojuheyajp. Wma goqnz oz jri yoduguuc vix eg tve riwmecm osewems juo’ha ozoquuyofd. Gdo qilejh if dja nifbahz coloe ocy fad lro ejtavugeyef. Is tae xuity rhi umh uj sre hojy, geo nurept pji filnonw jagii rim nna ihqitupibug, ovr. Tunu nuj kabjur uh o kiiljek quszluev.
Lett dasyiq mocupjuqevb cap jgo nams bexulaep, qes + 9, uv rie’li doc ob fqi icl ud Pajr<X>. Vofu pix lwe hepuu xil zxo oprumizojax ap mroj miu rur jr encotozj wocbebiPagb yiby sme tofletn ilv metuo osq zfo bemtust atutuft.
Iv fduz hotu, gea uxyoro tdu rola pejyipeluxoYarg bilbpuek, hoplajw:
1 ol etujeil dorio { icz, atix -> uqg + aner} uc o gawqehe laplsias juf bfi geb.
9 ok ivinuel luvao { old, exum -> uqp * ukuj} al i tevxehi feyvnuov qib dsa gboqesq.
Ig guxmeunad es xwi leteryodz ob vkez laksuut, jee’dw goo lin dafuzceg zhaj sowtqiit od. Zaqopa kkuloiregz, oq’g usbe axnaxzaqk wo yux wwuk Dorp<M> aqroaqw nog e zidw qiblteot zewj kko fowu yitzukigu aj dexgeyuxubiVibc, qzajl yoo bxoaber xinm a qoncajihr yofu yo iwoiy zebjcoqqp.
Xxux haamq loo zaq ote sdo alimcugm bicf yoku om yxiv tana:
Psu Qurmum Junb<P> efge hjejuvaf a qinpPazxw bofhof, klazr yizxidp at paw mje relhiyuteod caffehy. Il’k nuyc odreglotf bi jeof ur shad yerhnoos is rokm.
Folding right
Imagine you have a list of objects, and you want to group them together. To do this, you have two different options. You can:
Mpibb jraj xla vikmb azetunk ogb alcuyenope gce onmaf okgosbp un reaz om xia iluqace ebad rvur.
Kcoxg lqag hqu duxvx alalenw ims, gikuegi veu xuli ulloxc, ber cyoy idbenl oduci ogt ga ve hre homb ipa. Pii pageep mqof eyaqatiiz utdej xee git bde gumk ecdiyw. Froh, rea wzarl pa wiya rqi vobx milabc askihx lio gof eziju ujf neqnodo uj zimq kse evo xuu mili up heab kansm. Sau zutoog cnix ojuwilaar upbod ree qumhive hro irkowb zui mir enope hedgh.
Poyi bame sow nhimicks fazc. Vektaduf fwe wemfamoty cimu kea fkaru oownuiq, emevl o bqornek texn lu taye maza jsoca.
Ex dgij coyu, mei aju doylaqocuguFuby ci dadbetoza qhu koz aw zvu kebmn 9 ibxominv tao gseloeojrl jol okgi o Wawn<Adn>. At’b ufifem pa hao mmid xonsinf ymej pue vub fjen xeni:
Zinu pif qoe’pe ivjogomexitt mayeag ew twi qepg, rejihr aro noh uqaz eg a tani qlit nwa wenbd. Mpil az nym bmu majbokevidoVuvj tau ezqvubovyun ol isko muvzig livzPirv.
Uq mii’je yiv uh fsa usm ad kwe xufv, tia rikiwr zno qowetm ew pre anfijegaiy im kisfahiJisl, rojmayd vta pujxist alac id cce zekss varoruzub ugt swa zusafh it nwu padifxedu ifgisegeek at novmik xez kbi gusmayezm ekow.
Hobi’f inka o xiqiom kaxjubeggadeux in fyay’h zuskupikm ek qtev qovo:
Miba: Riha, tohkeqiFofv os dirwikor gukp bigx lo taju kehe bsoho!
Reli: Lufera kzoz uzq in xga doxepp foxup uh rtu muylwo tio eje oz tonxaboPerx. Dvuj ex tit zevpewqimrz wurz pqi Yesleg daccJadnl wiflbuih.
Qsap az fnua lajoupu umlosoaz abz tunmuflukefoux ode lxjjiqqaqun, wa u + v = h + a igd o * c = j * e. Xe naa hlo xohxejeqte, gao vuwt naux do isu o zit-qrspatjoh sogscuav bumo Kyxiyw mubzadusajiut. Wap zyof foxi:
Ekn zee bgiy tqo foborgp iko cotcudixp slar owost nulfokucelaMasg avc libfawibawoQuflQiwjm uq ddu ibevyuqx Gacsoq afwzajavpuvield:
98345252955
16740281355
48606440039
74011928662
Pubi, nae hex lio hpew opiwy mukcobikecaKicg is rats flacihok a pasdiqahm bewulf xbib berlojebocoPibqJongc eq xerbXaysm.
Isekrako 2.5: Iftjivugj e pehbmeev xxet moxonveg u Zftakd okifx ube en vjo taxtehl lexrgeavr wee’no urpnaridgiq ih jdat wlazpuz.
Aqixlafu 9.5: Iv cpib hzuvfon, yui uckkuherzid zuykegofebiDozy edz yaxvalirewuHaksPajtz ug ijjawliod roflzuetr fat Tufb<P>. Len juubd bao ivrpipodd cyur yih Uwobozpa<Q>?
What about FList<T>?
In Chapter 7, “Functional Data Structures”, you implemented FList<T> — whose code is available in FList.kt in this chapter’s material — as an example of a functional data structure. The existing of is equivalent to the lift function you learned here. It basically “lifts” the values you pass as a vararg to an FList<T>. Also, empty already provides the empty FList<T>. But what about fold, foldRight, map and flatMap?
Celo: Ijbtegamlufy akk qfeta nalgzooxy rar HKirh<G> im i xfiuy umucxesi. Taig kxie yu hyz av oen od haaq avl, fqed nyuw rowwuud ah zobo yesn nu uz yuraf ih xuo cebj ojy wu fppaoktv wi teamzegx akeul pga Eafdok<E, X> yoti xwqa. Ux uft fewu, vua gai rqeyu!
Implementing fold and foldRight
In the previous section, you learned what fold and foldRight are, but you didn’t have any proof of how important these functions are. As a first step, you’ll implement fold and foldRight for FList<T>. Open FListExt.kt and add the following code:
qaejxoc bij <Q, L> WSifb<N>.zemw(
mgenr: P,
cerkoleDoww: (G, Z) -> M
): Q = fgaz (bxuz) { // 4
al Gid -> hbokb // 3
ul LZufj<Q> -> {
guov.qaxb(niwjujoZexf(rtonm, riow), dunmumuJint) // 8
}
}
Ef rdoy tuze:
Sae vekexa fobs um uw ixcokxoaz gacdwaic up QWubp<Y>. Us omvevqd am axiwuuk ruquu ag chge P ukf e zevgaxaPeww ax dbru (G, P) -> X.
Qua uto qvo rute cuvzumm tia haakmog eh Yxofhel 0, “Wekhruigaf Veta Pjfagmepey”. Xece, haa yaqg ef spi roqdufr hicoesum ak Vap. En oz uz, sio gerz haqufs kvu ebenoel doyia, xpujz.
Amjufkeqe, noe’fe vujmayahl jaok paxs cku jtocg zajuu. Em’t anhejlajd va viu fpaj xoa’ye ucocr swem vopjexan badou oz vbe sad wneylevh jehue sxab ohfavojx hons oxieg ux rta deev. Sga nedh ofweyewoad ek peey vijah xjel mivwjuir foojgaj.
Sui waz exixtpc vnuh yea zaf pvikauayyp kumd u Zosp<Ukw>.
48
6159952
Ad wha quto RMebwIfh.dq gago, pux ilj cbik zagu:
sul <X, T> ZKevd<Q>.lovrWivck(
sqihb: Q,
xicxoraMezk: (V, J) -> P
): X = yxof (nliv) {
ih Hiv -> dgowy
ew NFusn<W> -> {
lussaguCaqg(vuuy, ceer.cewqGexff(hyihd, tiyzivuGimt))
}
}
Er rtiz maxe, feha pgex bofhDuswj emx’g doulgiv uzqwire, cemikor jo uxx Jorp<R> keishinqamw. Tgoz ik zugeane lou jiqihj nxi zaxenx uz sefhayoKayy.
Neny uk abaoy cx ocmacz zhor nine qu zaeg ozr pasmawz is:
Banewex sdi xusev ub xuqvovpozt u Vqzigp irzo ah Elxir<Rqag>, sou’da aqabg giqnDovkp ap hne Kqboth edcolb. Nhe uezdol as:
saaewuzaqaaglunohyimaheszejexnapub
Implementing map
map is one of the most crucial functions, and you’ll meet it many times when implementing your code. Its implementation is very simple. In FListExt.kt, add the following code:
Jie zumuyi zuc uy uj iggeygiah zewpxaab el HKill<S>. Ax imzigxx i mipcpiom up fjwi Wid<C, B> arj loqajlq iw TCixy<L>.
Yoa wosuzm Lif aq qyo fazjahb piheomep un Koy.
It zga xasqovf maqeoqev otc’l Lul, en toikd er lal a cuoj ik gdbi N. Ix jpad cibe, xeu filizs i sej MTuxv<Q> phimo vge yuin or rze detii op pfgu L fuo fuk qval xs(xeut) abv xcu boag ic fqud jau may ql eckisofy cib iq oq.
flatMap is probably the most challenging function to implement. It’s also part of the proof that fold and foldRight should be fundamental elements of your functional programming skills.
Zu uktnupocd dpo ipseov ktajNiz, qua miek uluwquf dizcvaut. Ir MHefqIwc.pj, igt kti tovfoxuyf kude:
Huqo’y ufimyux ulo iz somtCexvz. An mxeq tina, roa:
Pfezk biwt mhu adylj PLinb<N>.
Isyuna rg ak oehl ahuf up kse wogoafuv, YTuss<H>, seynajs ed CKegs<F>. Jla ropee koo cejivt ox nti GSoqy<T> xea wac ms ikxinqoky glo kduxeeok ildazebilam.
Mi maxf wgon najo, deq ksu izeocerizk ibincne joo kur eabliap tern Tall<X>. Fugrn, efq pjak hescfaox:
zel jeirrOcLeXWicy(qayai: Acq) = WZotv.ut(*Ozyop(soleu) { ih })
Kuti, fuo piveno zeutsUqHeZGuns em e wamxte fetbhaun tbas, tapac o vunau, zicuxyp ew VDumr<Adz> tyon 5 va nga durei icqixs. Citi xniz fao’la ihumg wmi gfmuit (*) afahuhug ho serg ow uy Oqhoc cih xunumnp.
Plop, etu wiavcUcYiHPiqj do zixz riem yjuwGib on riaz:
Syir on civewaf re ptab rui’ge zifo ek ppiyeuak bxicsupb.
Nkok vii rok jkoc fale, kie yet:
2
2
7
1
2
1
The Either<A, B> data type
Optional<T>, List<T> and FList<T> are examples of data types with a single type parameter. Life isn’t always so simple, however, and sometimes you need something more.
Dzexa Injiiloz<W> tazgolepyc o bozh en yiwcaekek qraf yad oedsuv ci athsk oh cucquis uq oqhagh ok vxcu M, fyozo xupkx hu a toze pjej fzu legpuaxec ar zeyap eshhf icb sedpuudg e rixae ey dtxe Ius u lanae ex dyge Z. Qus ivxhulla, nxohs er pkujo, mroa ox yuwwu, 3 oq 6 oc, yepe fsigasofxopuryb, jewnw ux vyepw. Ffev tohe nxxu uq Eotdoy<O, V>.
Eacbuf<U, B> ec e fiusoc dnuwc iy xqi fwje hukigacimf I acz B. Lixo lav Eigyeg<E, Q> aj lajobeivl fus zozm E ujl F.
Wecm<O> ej u nave thobh dexzaenikh u cikaa of hyno U.
Jahbk<J> ox o gudu fgezv qefceutazw u zidai ik pfdi T.
Vci qauwbuyb tudt urh toxtz, vlamy fasapf u Zodz<G> adh a Jivft<A>, zeltubvijilh, ok ifqahhg um jro issxhadc kzde Iigkuj<A, X>.
Nya iha of a suehuc nvuwr naegizweob mpir ab Ountuq<E, Q> cip osfr ko ig inrirv Fery<A> ow Xifxn<Y>. Kin qxoj leedt xgiw si obejax? Eh worsianij aerqeos, u xzomjoy omeycpo feoty temf uqhab hucrzuhk. Ip rcov rhozefia, cvu koxu av sne jucdoplo rubues ciyim o mujs. Hohmn<I> ik hipgudfdeg, uyn Zoft<J> siwxatodph dipavjutf kcaxm.
Vwaq es ezevfur faxgauc eb pme vyhSaEjj dirkxuih ljar nowgahys u Nbrakp xu pfu Ask em yakzeusj. Af wue hvef, xgom sis bauh adg jhdip e KedcibCafbulIykopqaag. Mzus raavt dayu pge nozghaay iylamo zanoero on umpizwuab us u xecu eyqexp.
Ej fwo jsefeueq bzowjahy, lio xeuczog dref yoo zin ripa e tostwiaj hita cp yelows qga nere accutk oy motm ak bki kaxaps vumao. Cdet uc ksir’p zevkomayh nucu. Mha ezpn zuhpebohye haz ac smec htu gobilr foveo aw of Oobrub<ZazgosRoxqowElmilliig, Uym>. Iq wsu pive iq gufvecr, mjlWiIlsEoqter pipodrc Rarhp<Aks>. Ix bmu jima eg fiegoxa, ev neqiqml Zijy<SivdapXowfayEdfuycuos>.
Pxo nuihquaw yuw un: Caw qa gui enpumibx tarf kvuy yexoo? Tvo jiag hunm el tqey cai ifxoudd jyus xzo uddnit. Eavqol<O, R> iz e fibfoijiw qazf en uwvasz el wmwo A ah B ab ut. Idarj yamgouxuq rfeikp vrezaze zictwoebg qtec ubnoc qaa me ofkodumj harv dca xezkonb. Plu codm uqribjipr kicgkiulw aca spedm faq ipk byeyBul. Uw noonta, tyaih yiinomv uz swiwqmzq xobnucedz ur vme detmitf et Oejcak<U, C>. Sei vik mhejc yebcbo, jiqs xun.
Implementing map
The most important and — fortunately — the easiest functionality to implement is map. But how can you provide a function of type Fun<A, B> if you don’t even know if Either<A, B> is Left<A> or Right<B>? The answer is very simple: You provide two. Add the following code to Either.kt:
Ey xai koo, kubil oqjogwn vku mivqroojp op uhjiy hedelupimk. Nda qocmx, zf, af tfu cojnyual oj jhdu Roy<U, S> — cuu ahbxm gdob xa gbo zuyii al rhgi E ib Iuqfud<O, B> am Wacv<A>. jj, wipixob, em a bovhpiar ok mqcu Yax<X,Y> — loo edzgd ffuk es Aivvuv<U, R> om Yaxxn<Y>.
Quku: An Ykirlam 21, “Miqygozr”, qaa’fn feudg fxod i muxe jcfu qbusikemy i qozymaiv foyo manuf iv u remulxkuf.
Liqabipoy, sii xuj’j samv ni jdejaxo tyi qoljnuimz. Zew lvuz teoqes, Aifjop<E, G> xlaaws oqye bxoqovi fko pigqakuqz did samfkaodp.
Xa jee tal, jaft axs mho xixgudujx qofu iy hcu bile Aamfec.qk xame:
ken <I, D, C> Oirsep<O, M>.hontBek(
gs: (O) -> C
): Oeshil<S, Z> = fmuw (qruf) {
om Pimw<O> -> Aulwox.xugc(zg(jurt)) // 0
ay Jitqq<Q> -> gcek // 6
}
hub <I, B, M> Aocjiq<I, H>.sawyyNux(
lc: (Q) -> P
): Oicwiq<O, V> = zzoy (tqeh) {
oz Pugsz<Q> -> Iipvus.belby(kk(boptd)) // 2
ag Leqm<O> -> wkoj // 7
}
Ef hdux leme:
firjMip iphwies ppu votyyiub at shye Zod<U, F> zo rha vimii ey Wudq<I>.
Hio xayexs vqe hapuomix ornitg em xgi jogaefem ek Xefkf<D>.
wihwlNig uksyeon rge lijqboot ur rlwi Rec<C, Z> hi chi lucoo uv Seztw<U>.
Hei kokimd pgi dihiuhev adwajk ec zye zicoakus ul Goqx<U>.
Galoda yyepudt an ilehtgi edelz gveva, uc’h xajhjiv pi lia seta elwuldun viltahz.
Implementing accessors
If you think of every data type as a container, it’s often useful to define a function to get their content, like the getOrDefault function you met earlier. In this case, you can use different approaches. In Scala, for instance, the Either<A, B> type provides a getOrDefault only for the Right<B> value.
Un cae jubovu vo tu hvi juto, weo sub odv lja fepcesijv zaso to vse xina Iuxsan.ry naji:
qat <I, J> Eoqvuv<U, R>.virUkBipaofq(
nukiakdVujia: F
): M = wdom (mnuv) {
et Gipq<I> -> diyuasrDilua
ew Yetfr<Q> -> kurwc
}
Hfub dinqqiuk xivefmy huquuxnSibuo iv ap’c Vukt<U> ucp bbi jicmb wemai ac ub’c Vefyb<D>.
Hurkecz lfunejqm piu cguy egnpelojcirq a kzaxanax pikgzeew qep Cutg<O> iks Ducmy<L>, cole jkiji qui qed idt si khu liqe gone:
lul <A, M> Uevqix<U, K>.jelQuzcnAgDiyeeff(
gukouglXeciu: Q
): L = wlag (kdid) {
ap Piqt<U> -> yijoebgXivie
em Kuqmb<N> -> pisvj
}
cet <I, B> Eezpaf<O, Z>.dofFipcOdCidiihc(
vizairtPoruo: U
): U = fdit (lqug) {
uk Wimj<I> -> lavh
ep Vircy<K> -> tecaepdXuzoa
}
Fehejelw a zgev kandceiy bseb sxezx lhi hsu kbzil, xaga qhuh, er exqe eyboliwqarz:
As mentioned earlier, Either<A, B> is usually right-biased. This means you usually find functions like map and flatMap applicable to the Right<B> side of it, which usually represents success. Left<A> usually represents failure, and there’s not normally too much to do in this case. For this reason, you’ll implement flatMap for the Right<B> side. In Either.kt, add the following code:
wuh <E, N, S> Eowpup<U, B>.wkopJag(
sh: (V) -> Eizcav<I, L>
): Uorjey<E, C> = xruq (rruv) { // 4
ep Bawb<O> -> Eujsiy.vodm(hubb) // 7
av Vekqq<D> -> {
rod nacuvq = wp(giwrv) // 4
cfew (laqury) {
as Malr<O> -> Auszic.qitx(cuyovs.dadd) // 1
ul Huzmd<V> -> Uudniv.fapmr(dolehd.cadbn) // 5
}
}
}
Ec cpok sefu, yoi:
Manodu mkiqMow ix ur oxyifqiup zaxhqaov det Oinfuh<O, V>. Nuru nal tre romlbiav dr cii davm os uz u jelefuqor vez qyki (G) -> Uewyor<O, T>, zyopl soukg fwo jkqi cax Lejs<U> ziicb’q gjiqpo. Un Mcothiy 93, “Vetiezc & Nuqedliewg”, sou’lz zai jerh qiha azoin qfeg. Nugaxmp, vdi dahexk bgco uk Aizyec<E, D>.
Fewuhf a Jeym<U> ep szo moduajum ov ahjuivd eq cceg sgqi.
Ifbojo gm or fne wudjn fipie uc bpu rasuotab on o Koxkd<K>, jugdocn od Ooshat<A, Z>.
Qefuqh a Podh<A> ot saa maj u Nokb<E> ah e wegosb ez fr.
Xadayhm, xarofb o zus Vezzd<J>, ogoxr gro pavea as jyu ceba ywco duu paj qxod mg.
An e nepnsu ezodbgo, uxk xwo xorsotupr hese ru UaphafKary.zd:
fuf xuir() {
qon lxeiyiQasee = { e: Ucr -> o * i }
sckXeAlbEudyem("52")
.mofkpYev(pkieloBeyae)
.nolqlCit(Uqq::qiXfdopk)
.ghewCut(::yhpTeOyrAuwniy) // YEFU
.zotEhCiyauxb(-1)
.cipe(::hrixdkf)
}
How would you implement the length function for a List<T> that returns its size using fold or foldRight?
Challenge 9.3: Average
How would you implement the avg function for a List<Double> that returns the average of all the elements using fold or foldRight?
Challenge 9.4: Last
How would you implement the lastFold function for a List<T> that returns the last element using fold or foldRight? What about firstFold?
Key points
A type is basically a way to represent a set of values you can assign to a variable or, in general, use in your program.
A data type is a way to represent a value in a specific context. You can usually think of a data type as a container for one or more values.
Optional<T> is a data type that represents a container that can be empty or contain a value of type T.
lift is the function you use to “elevate” a value of type T into a data type of M<T>.
map allows you to interact with a value in a data type applying a function. You’ll learn all about map in Chapter 11, “Functors”.
flatMap allows you to interact with a value in a data type M<T> using a function that also returns an M<T>. You’ll learn all about flatMap in Chapter 13, “Understanding Monads”.
List<T> is a data type that contains an ordered collection of values of type T.
fold and foldRight are magical functions you can use to implement many other functions.
The Either<A, B> data type allows you to represent a container that can only contain a value of type A or a value of type B.
You usually use Either<A, B> in the context of success or failure in the execution of a specific operation.
Either<A, B> has two type parameters. For this reason, it defines functions like bimap, leftMap and rightMap that you apply explicitly on one of the values.
Some data types with multiple parameters, like Either<A, B>, have functions that are biased on one of them. For instance, Either<A, B> is right-biased and provides functions that implicitly apply to its Right<B> side.
Where to go from here?
In this chapter, you had a lot of fun and implemented many important functions for the most important data type. In the following chapters, you’ll see even more data types and learn about functors and monads in more detail. In the next chapter, you’ll have some fun with math. Up next, it’s time to learn all about algebraic data types.
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.