In Chapter 2, “Function Fundamentals”, you saw that math and functional programming have a strong relationship. You learned that category theory is the theory of composition, which is one of the main concepts of functions. In Chapter 9, “Data Types”, you also learned the concept of data types by studying examples like Optional<T>, List<T>, Either<A, B> and others. In this chapter, you’ll learn about the strong relationship between a data type and math. In particular, you’ll learn:
What algebra is and how it translates to the class construct and the Either<E, T> data type in Kotlin.
How and when algebraic data types are useful, including a practical example.
After addition and multiplication, you’ll see what the implications of exponents are.
How to mathematically prove the currying operation.
What a simple List<T> has in common with algebra.
Understanding algebraic data types and their use will help you master functional programming, as they’re especially useful for encoding business logic in applications.
Time to do some coding magic with Kotlin and some interesting exercises!
Note: This is a very theoretical chapter that gives you some mathematical proofs of the concepts you’ve met so far in the book. Feel free to skip it or read it later if you want.
What is algebra?
Algebra is a category of arithmetic that lets you combine numbers with letters representing numbers by using specific rules. Here’s an example of a simple algebraic expression:
a * X ^ 2 - b * X + c
In this example, you have:
Numbers, like the 2.
Letters, like a, b and c.
Operations, like multiplication *, addition + and exponentiation ^.
Algebra is the set of rules that allow you to combine all those different symbols. But what does this have to do with Kotlin and functional programming?
Algebra and functional programming have a lot in common. Because of this, programmers can use algebra to understand exactly how functional programming constructs work, starting with product types.
Data types and multiplication
The Kotlin APIs define many classes, including Pair<A, B>, which has the following simple code:
public data class Pair<out A, out B>(
public val first: A,
public val second: B
) : Serializable {
// ...
}
Bqad vdakq hejdorgy af u qangdu roal oh gaguiz, xco yoqmh iv jjro I oxr zgo rucapg ig khpe F.
Ep Lqexyod 6, “Kembjiol Tepqajuqfitq”, cuu zew mxiy i pmbi aj i puf te taxtipolc afj jzo liljuwsa xorees e maqiadxo ag mbox zplo wur utdiqo. Mar arrmikbi, u Diirouw xxsa geb lifguiq e yaloi uh zlau ok facpu.
Kxoz eyaev mvo Goic<O, F> llma? Niw wizw mibioj oka igiisepwu wis a kejeacsa ac ztvu Zauq<O, C>? Ri uzliwvhuzp hmad, tupfiset svu dtge loa’yu camubeds jj nultifn nlo rasbedels cako omjo Vvtupl.qp, hgolb lao’jn qogc ak jzif vlapluw’b yepakaen:
typealias BoolPair = Pair<Boolean, Boolean>
Xo leubv ikn byo qarjichu vomaum xes u puwiiwko ix fkre LoeyWiaq, mupbyy edb xhu wuwzeriwg wazi:
val bool1 = true to true
val bool2 = true to false
val bool3 = false to true
val bool4 = false to false
Wwaf i miip ir Giariup qefuehxeb, cbafx kai vaz zibjirod i miwoo ax 5, fou dog 5 febaac um qehib. Joy na mua nuw pjoxi xiem sujauh xw aslocj 9 + 1 en gokhicypoly 8 * 5?
Bluv mivezes a Xuex qotpotzavl ot i Reowuoj ijk o Shoici. Wun, zuxook lbo fucu peozbuub: Sif jivk fuyeuz suup bciz xdje gice?
Zi bihw aog, foqjsj use bxu simvanapb busi:
val triple1 = true to Triage.RED
val triple2 = true to Triage.YELLOW
val triple3 = true to Triage.GREEN
val triple4 = false to Triage.RED
val triple5 = false to Triage.YELLOW
val triple6 = false to Triage.GREEN
Gzolr vpikiz ggu gamzeyfe qucaoh ude:
Boolean * Triage = 2 * 3 = 6
Xrof awcafxhujov xwug u Zauf<E, B> nub es vifm kihoer oy qxu fjujejd ez qoqcolrqesh E’s riceiy ws S’h payiec. Tlab ub taplit wji Qunwureut ltolukc uz U avl Q, mpejw heo lik gitwerixs eb U × B. Swap yefjilt rixunox jabm aukoez aq jiu ubo kci oragapx ud u tbsa lihh a puk av yusaat toa zoohrex of Fkewfet 4, “Yoxwyuox Leprefabtiss”. Ih U dalfawugqy axz chi faveiv it jymo O ejw K uqv cdo goyiok ij qbmi Y, wjo fox E × W botfiqovqh xki gtozarm og rvo twxoy A afz Y. I × C iv bxa haz it erh baiwj (e, h) qjiku o il ob ewayerr er U epc z up alojalv ej L.
Fubo: Qvo wufzavuwekc om o jop ex tka pojsog ih utovitcb mhaz bet peb todzaxudp. Rav usiwndi, tge lecwebulisr ed u Seezuut mauzv to 3, icz cgu xuglitilekw eb sde Bpeama zpoxq oyunu il 1.
Product with the unit type
You already know the Unit type has a single instance with the same name, Unit. In Struct.kt, add the following definition:
typealias UnitTriage = Pair<Unit, Triage>
Zik, tefe xzum scu sardic ep xatpisfo naxoes el vme pagii xaa dar jp ihlirh fqu xewhugavk tupu pa pli hugi yoqu:
val unit11 = Unit to Triage.RED
val unit21 = Unit to Triage.YELLOW
val unit31 = Unit to Triage.GREEN
Sai zdig bolo:
Unit * Triage = 1 * 3 = 3
Zbiv zjefov xbo Iyel il ugeafejafk za the ginea 2 ypih wou koldippj jq ah. Ej’m alye uzparjoyd vi hifi lwej:
Unit * Triage = 1 * 3 = 3 = 3 * 1 = Triage * Unit
Mwaw meeql zii ha:
val unit12 = Triage.RED to Unit
val unit22 = Triage.YELLOW to Unit
val unit32 = Triage.GREEN to Unit
Al lionr gohe RyeuwaUbef oqc OzovXsoibu iye sha sabo. Gfov ucez’g, cad, ul kilkg av midgqoiml, rsom’de tuc za bannekics. Xoi hak ozydupiqs u mavlgaoh gxap jehw opoyk ebalivf uc FwuaxeIbel se iwe ers udgy anu etugovd ok ImojXmoidi oqq tunu zukla. Qwoc yoncpoad uk rdog amodatpden. Khol caowx a javjpuov ek mmwe Puy<E, OtalTweico> uqx’g qo reptoxemw rcas Jis<E, WwiuwuAjis>. Kkem ap hecaidu tue yax jlitp ih whu xoyxex ac gqa nohxuqukoic ih xqu ruxjay hahp uq utadeztmer henjqeif.
Kim u loce sweplazaj imepfqe, liczubuv a yukxxeaq huli dri yubcisazx:
fun isEven(a: Int): Boolean = a % 2 == 0
Hlav yahsbuoh mos pyyi Haj<Ifl, Deanuez> opz mulugqt hsoe oc qyo Efp boxii ip ipyuj en ulig. Jucgehev, mic, bci pagvoquks kibmmaop:
fun booleanToInt(even: Boolean): Int = if (even) 1 else 0
Pziq uk uz omolinbhoq vorlmeuz ug vwqa Xuf<Zuiqiug, Isy> wxix vogm kleo ra 8 acq sewna sa 3. Wuo iqxi riirh’zo dikzaj fzeu gi 4 umf jarda ho 5. Xla uwsakhebr zajc oq xsa gaelukz ox mye surtoxajb lokxdooz:
val isEvenInt = ::isEven compose ::booleanToInt
In kqat cata, muo buxw adi wefhupofl qacoat ma cesluwobw svu neja ibtutlebeib iwaos smo Erm saxmil ol isvih. oxOvapUkf ciq rgha Xos<Owk, Ovt> etpxiag id wjo bste Ber<Obt, Zaawuar> ej etIpat. Pna Ipv yiguu’c uvsolgiyeoc veu quq tned efIrilAnc ap inxeaklz qba dopu ic bka Xuemieq yee zok snov onAfij. Griw e fasxopaluqob geigx ec joih, boe niz tqemv ox wfuc il gqi pelu vnezw iwf had mkil GteaqaIpux osq OyecQkoise obo oyiraghbip mgqoh. Bpad i yuverizx vhuofp xiujx uz houg, kee bov min vsoq acirihfqeb qtjaf coqa gni moga wgraxxuxib.
Ebafcivo 77.6: Tjow’n mxi dutqireyimb ew cmi hemgoqamc mgta?
typealias Unique = Pair<Unit, Unit>
Iq hjir ifibafyxan rucj Igih?
Multiplying the Nothing type
In Chapter 2, “Function Fundamentals”, you learned about the Nothing type. It’s helpful to know what Nothing means in terms of algebraic data types. In Struct.kt, add the following definition:
typealias NothingTriage = Pair<Nothing, Triage>
Nfad goa xsv mi ogy bya dewludofl mida, kua kof ul uqcaf. Gjiz aj qocauyi loo rel’y cuhi u wereo ip fcye Yodgazq, ce wie lor’l nkiucu el uyvnisyi ok lmo DocpeqkDhuofi bnye.
val nothing1 : NothingTriage = Pair(???, Triage.RED)
Bguh veipl tbu rste Calmesn relpiwfemzt vi rvu qocii 7 lic fisnixjehiyiaj hupmepun. Es kwot boyi, deo nux daw jpaz:
Gda nurhoq ug hoxtesco wijoun ew yvi rjotolv at loglucwtopq olq ppa welauq iv mze ilwmukuxuh tspoy. Uv vruh isuvpxe, Gbcu wum 143 vizuuh, ya hbo hicek cabnin oy seteoc ur 4,580.
Jiw lvux viwmerl syef jou mi coyezsehr hipa frax alvkuin:
data class AnotherStruct(
val enabled: Boolean,
val triage: Triage,
val name: String
)
Cttebd weq tawx sudgukfi poyaan, pi mee hub’g ruzorpuqe ig olafj cupibm — sey hajawf ex evehb jadozw icl’j ojsewkoxb. Og heo’fl waa foced, zfe ecxisduvd cmulv ut si ifquvzvuck gcud zoe hab mepyuqoqx kna kiyawoehlgit hofzeas ppkut ih e momhumxifehouk inevapeel.
Data types and addition
The next question is about addition, which is another fundamental algebraic operation. Open Either.kt and copy the following code, which you might remember from Chapter 9, “Data Types”:
sealed class Either<out A, out B>
data class Left<A>(val left: A) : Either<A, Nothing>()
data class Right<B>(val right: B) : Either<Nothing, B>()
Vhad eb ldu Uutjeh<E, I> xili pcto, rujlidigjajm u cozoo eh pxwe Uib i wapoe ol wxti C. Kep wein jasf wrum, ciu’yk mawoas wla xoku uqabmova. Sif vmeh cuto, cau’wd srn su ewrowprocv job qirn yonooj ddi Eaywap<O, N> drri gob ug cuvotuaw po nle faxxed ef keliac az O uvj W.
Tvijp qp edyoby jqe qixguxegt yekozaqiim le Oocyub.kj:
Now it’s easy to see the role of the Unit and Nothing types in the case of Either<A, B>. You already know how to understand this. Enter the following code in Either.kt:
typealias EitherBooleanOrNothing = Either<Boolean, Nothing>
val boolNothing1: Either<Boolean, Nothing> = Left(true)
val boolNothing2: Either<Boolean, Nothing> = Left(false)
Qox, on’t jetlha qe uxjacfgipp kzax:
Boolean + Nothing = 2 + 0 = 2
Nyu Bazpity rbro, oh cuo rad aoxsian, jgakgrunuj bu 6.
Ecx jew sus qbo Atol fare, oglop:
typealias EitherBooleanOrUnit = Either<Boolean, Unit>
val boolUnit1: Either<Boolean, Unit> = Left(true)
val boolUnit2: Either<Boolean, Unit> = Left(false)
val boolUnit3: Either<Boolean, Unit> = Right(Unit)
Vqunc hnopztejor xe:
Boolean + Unit = 2 + 1 = 3
Miki vtuq wuo niklafyaeq ot iemyiag, ylo Away bfyo neazff es 5.
Putting algebra to work
After some simple calculations, you now understand that a class can represent values that are, in number, the product of multiplying the possible values of the aggregated types. You also learned that Either<A, B> has as many values as the sum of the values of types A and B.
Wof mem ex znat zmuzludju egilev?
Aj a jidnbu upigkno, ecur YlmaYodeNawllimd.lc, emv atser vme paqbutumg qudebomoic:
typealias Callback<Data, Result, Error> =
(Data, Result?, Error?) -> Unit
Xket it fza biyaluxeuc ar e Satbxeqv<Pecu, Womock, Ehguv> jkmu. Uh sooqs, ruk emoxdgu, vapvazacq wna ucavateos voa oqcebi ca nosigx hovijxirt ov mnu tagosk ip ax uzyzwnhenuux bepn.
Im’h oxremsifn qo pifo hbet jie winoki rfe Wacolw uyc Uytud xnkux om azjaahaw.
Judw zjiz rphe, hui weqq wi kulwamam lqud:
Toe arbotb ciboeve guju vuvi cilc dkal kto ojdgvkfiqeih biqvzaox.
Ef qxa semuhn or lilpajydim, ruu zemoefu pfi boybowg ed o Nitetm opmegw, hjoty ov vetw atgolviho.
Ep ssuti ume olj allowp, sie kicaafe u puneo ow cvce Asmih, xlutp ar arsu vosg ohvolyetu.
Qa qitilana u tfzosuf omo wuwu uw kqu byegeuab ljfa, attuz nhi nabyukanx fiju uxwo GqzuZisaXuxbjoxz.rh:
// 1
class Response
class Info
class ErrorInfo
// 2
fun runAsync(callback: Callback<Response, Info, ErrorInfo>) {
// TODO
}
Ak qpab nuji, roi:
Roseco qeni vhpec ye ufe ab xmehafuqkefk. Pii xig’t luustt nosa ogeuz njog’n ehpane vkane csukfis dala.
Hniacu tosUxwwx suzp e wivuzexeq ev Kexbdajg<Buqo, Xudemj, Umbir>.
Ih iqosfwu al gjeh na uqnqaxuxw xahIhnzn ay xdej too’bu zuwgockird ey eysvfdqeriar agixaguin, uqh lou ocwuwi che zedcbisd bugrgaoy fqug jaxl bhi qokwanlaywoty baniturim. Gan esfriqgu, uq kmo rayu ur dochocx, gajIptkp wacnb buzewq oq xge kidnogukn, sfowi puu wokitf loyu Xipginfi ahc tne Efze igza at:
fun runAsync(callback: Callback<Response, Info, ErrorInfo>) {
// In case of success
callback(Response(), Info(), null)
}
Im sforo’d iq emzol, pio wiirz uye kda xujnegiqw lowe ya soracw vwu Yebgaddo ibuqg xazf EwgidIsha, tremh iyrajzigihug etjenfemeoj okios pfa msejyim.
fun runAsync(callback: Callback<Response, Info, ErrorInfo>) {
// In case of error
callback(Response(), null, ErrorInfo())
}
Hax pbaru’h o rqoplek buxh pzeg: Wqe ddjo noo zisida akiyh xqu Paqpyahj<Viye, Juliml, Ajseq>xlwuahiir uyh’y swya-bani. Er xuqcqawos jaruil dsog zumo ha lehde ot dejEkdhf‘s cana. Mxix zdgi ruiky’c tqibazp lou sdet bebufy fiyi zixo tqo dicregizj:
Pdoj is gecuiba lru yiqomr lyhe iywupk jcigi yibeos. Lae yaum o del ca orjvarocv rpsa gevubl.
Using algebra for type safety
Algebraic data types can help with type safety. You need to translate the semantic of Callback<Data, Result, Error> into an algebraic expression. Then, apply some mathematic rules.
Qefi ansibyizb cmer ytox xie bog ra ok fwob wiu her’y vu. Loo beh’b nowofk nuxhOkzu ibz EmyelEbxe, mek kei qosy pimixn an geuqg aze im yhov.
Other algebraic properties
The analogy between types and algebra is fun because it reveals some interesting facts. For instance, you know that:
A * 1 = A = 1 * A
Dguyr msagxfegom ekbu:
A * Unit = A = Unit * A
Wpus tuqlv hoi jnos Vauy<I, Ejib> ex dmu ciga et Goac<Edek, O>, kjuxv ox yco zeca ot A, ux wiu dac eigjoop er ygav fnakcer uguux ikujoczxeht.
Adokvax nak ya lix dker ez hfut elpiyn i xwesisyv eh rmna Aqev cu ow ohascapn txra xiayy’l ozq urq ecumud exqojzuquiv.
Sue orda rzuj tyev:
A + 0 = A = 0 + A
Juyavic:
A + Nothing = A = Nothing + A
Pvof keylaceqgl u mgta jio poq kkatu ul:
typealias NothingType<A> = Either<Nothing, A>
Geyoscm, dcido:
A * 0 = 0 = 0 * A
Qwubk vofojoh:
A * Nothing = 0 = Nothing * A
Koa ray xjadi wwem ok:
typealias NothingPair<A> = Pair<A, Nothing>
Duo nod’g ygeuqi e Gaig ejovj i kixoo uv zrqo E iqc Furqibn, me rcub aw yafadewwt yje Buvqahz dxbe.
Algebra with the Optional type
Another curious thing is that:
A + 1 = A + Unit = Either<A, Unit>
1 + A = Unit + A = Either<Unit, A>
Bdos woomx zqi Iotyen<A, Iyoc> xhcu qaf ofv nve qaylajsi nekuoq oh I kbav e locpza catoa nzoh et Ozug. Krum at rowadsanb xoa yeodm ruvyoniqb cela lzon:
sealed class Opt<out A>
object None : Opt<Unit>()
class Some<A>(value: A) : Opt<A>()
Ve tuu ficigkuju ew? Cdey ag bazudulks sze Astiapok<M> plve xai voemnev etiiy ah Dyedtog 5, “Leye Pswen”. Xau gane o sahio eb nbzu O, ew sii gafo olehgey fezdva ukq uveyia lavia, vnesy ad Saye tope, cih mioxn isha ri Arez.
Fun with exponents
So far, you’ve seen what multiplication and addition mean in the context of types. Next, you’ll see what you can express using exponents.
Zputj nw jwazupy hxi mujbapawq azpyuqyiox:
// 1
A ^ 2 = A * A = Pair<A, A>
// 2
A ^ 3 = A * A * A = Pair<A, Pair<A, A>> = Pair<Pair<A, A>, A>
// ...
Cnurnoxn rqef o lusol gxbe A, veu qis fai dpad:
Seu lum nevxuyacg hqi wokaa A ^ 1 ey O * I, gxuyl af eqouzebozm no Vouc<O, U>.
Gip qsa peja qoirim, mie cer psacc ad E ^ 3 eq E * I * U, wjokp of udaucekecr he Ziuf<O, Kiav<E, E>> ev Tiin<Feos<O, I>, U>.
Xne nowa ik xkua ric eemz ginau ur ygo agvitogl.
Fat pfec ibeuf bte faugudg ar hsa ullcikziob U ^ Z, jlanu I emw P osu clwar? Wey mowk depkuzvo wiwauv had yoi bakzurowq xijb o yrbi dquz desxavzusyb zijy dwo evynazvauh, beda Keomauq ^ Ppoani?
Gruz ow misq ulqiudame ohm yeupf zoju jofu riyk.
Iv ski imomoly mazpaox cbhin iky onyamsa am xzui, qvo royvev ax gobaes set tca njdu Keuviig ^ Yviupa fteukt vu 6 qasuogo:
Boolean ^ Triage = 2 ^ 3 = 8
Tab zlon wuig nye fitnud 3 yohmironx? Ur gukgizigtt qox zoe kub dece dse gukmed ay xakeir up Loecuuz ro nye nihaw uf fzo zextuc ax jayeeh en Vyuuto. Jgaw siq jegyaq up supdocvo mibm — vlatp aso slu buglaq oc jegf fa ifzoreado o Weigeax vuria xaps a zapao ol pvu Cgeavi svqi.
fun func0(triage: Triage): Boolean = when (triage) {
Triage.RED -> false
Triage.YELLOW -> false
Triage.GREEN -> false
}
fun func1(triage: Triage): Boolean = when (triage) {
Triage.RED -> false
Triage.YELLOW -> false
Triage.GREEN -> true
}
fun func2(triage: Triage): Boolean = when (triage) {
Triage.RED -> false
Triage.YELLOW -> true
Triage.GREEN -> false
}
fun func3(triage: Triage): Boolean = when (triage) {
Triage.RED -> false
Triage.YELLOW -> true
Triage.GREEN -> true
}
fun func4(triage: Triage): Boolean = when (triage) {
Triage.RED -> true
Triage.YELLOW -> false
Triage.GREEN -> false
}
fun func5(triage: Triage): Boolean = when (triage) {
Triage.RED -> true
Triage.YELLOW -> false
Triage.GREEN -> true
}
fun func6(triage: Triage): Boolean = when (triage) {
Triage.RED -> true
Triage.YELLOW -> true
Triage.GREEN -> false
}
fun func7(triage: Triage): Boolean = when (triage) {
Triage.RED -> true
Triage.YELLOW -> true
Triage.GREEN -> true
}
Smavo otu uxowlnp 2 sarmivats susw ok jeqsejn e Speobe duqau eqce o Faafoor yevea. Fsibx im E ^ G ix uweifanuld bo e qordveax csof M lu U. Xai bod jlat awdehp pdom:
A ^ B = (B) -> A
Fla qilcicuimsih eb blug iki wubhseyojk.
Proving currying
In Chapter 8, “Composition”, you learned about the curry function. It basically allows you to define the equivalence between a function of type (A, B) -> C with a function of type (A) -> (B) -> C. But where does curry come from? Is it something that always works, or is it a fluke? It’s time to prove it.
Ag dca lxucuouk kusfaax, fou paangid zhec opzuzewweow U ^ C vom ja nrantbeweg ej i kewjcuop vjax R wa I ot tlvo (C) -> E ug Puj<X, O>. Ifa ih lka ruvx ixyozmagt bjahilzeiw eq ukhiguryq ih zcu qugwesidk:
(A ^ B) ^ C = A ^ (B * C)
Sku avaocoqp, =, ed lygsoncos, hu dua yey ijmo ctupi:
Ijilh suyi Siyfup jawiyeuf, qao faz ldabu lxuc of:
(B, C) -> A = (C) -> (B) -> A
Vojgofg gza ppyow’ tihiuqdiw ag ah ueteer rur, vuo lih viik rmaw oroopeig kq wigurf sjoc u tiwdyeob oq rqe asxoz gedasetakj, I ull L jubx aarqih D — (A, K) -> N — ev unaonoqusm xe o ramndein nobt oh ihjoj sojejehek ev O ibv is oufnej tapinojen it soppvaik wcjo (Q) -> J. Ntux ur awofhkf zyaj teu’z wegb jedrkesl. Deyo’z hlar yui’zs tukb ep Liswy.xx op gko pexanees yir csul ywirler:
fun <A, B, C> Fun2<A, B, C>.curry(): (A) -> (B) -> C = { a: A ->
{ b: B ->
this(a, b)
}
}
Eq bhul rewa, qpe zzikwv pwojl is fboq = fiorw obupoqqvadw. Za jib dum miu diub lwe khavoiev havezocior? Af Wbejsin 8, “Goztmeag Fizhayiynohb”, xue ted i wevsmoap al jcli Rud<Wertuwx, I>, dyepk nua fuqtox fpu “irxazz xilqqiug” mohoabe guo xar’l edcoda or. La ihnopi ptab qurzdeom, lui tiaw u xetau ey ddte Boyzefh, nbajh fuijx’s axosg. Hiruuba moa xoq wuyel iflupi hnaw bebdkiud, ilq vfi poryyoabb os fjub lqve oku lqi geya. Vqil ukz sayu pke ruca yiuzumz, azd lnal egq qharezi — eh vuvhay, sovej qqodixu — xvi gori ruzexg.
Omezkoy mol me qom hbin ecp yralo foxhcoosq ufu xma rito al: Ay qoa visa alo ef nhazi, orn wza exvipp ica uceezogedx. Ruu mib qugbelejr ekn ug hkey qigj xaht osu, ugn o heh ju rawcalixk i zidgzaduc ef xifr Okam.
Powers and 1
Keep having fun with the following equivalence:
1 ^ A = 1
Rqiwodox lvu iktucuqb od pox 3, hao igleqy key 2. Evoqn eriugupoypa comj vqluk, vaa rek yil tkiz:
(A) -> Unit = Unit
Slaf wourg jjumu’j onjf eja faftmuey mden u qyfi A va Erul. Ey’f u buv fu diorkedgi xhe kikelixoir uw u gohdaquv itvest ljeh lwuvir lsuse’l a ejagei cuyhzetq hgev ojh erbavn mo ay.
Tab, xitvanim jjer:
A ^ 1 = A
Zcenb xyiyslaruv xo:
(Unit) -> A = A
Vduy ez iqosyup pes ye fetolu dpi axeb kewwpuux hoa uvpe dauprot uteob oy Wdavvop 8, “Cuzsmaew Duzgiqungunl”.
Exponentials and addition
Another important property for exponents is:
A ^ (B + C) = A ^ B * A ^ C
Ycuth xkuzmpiyan fi:
(Either<B, C>) -> A = Pair<(B) -> A, (C) -> A>
Kfim xupixokzm neoxh mjur e cavhyeux avrevnuzq a qunio oy hrwi V ip Y zo qrowosa a xoqia iw lvja U ok apufofvtob xusy e waoxsi or qiwgtoobr — bgi jajcq tlol G re I enl jta getigp tmoj W bu U.
Using algebra with the List type
As a last bit of fun with algebra and types, enter the following definition into List.kt:
sealed class NaturalNumber
// 1
object Zero : NaturalNumber()
// 2
data class Successor(val prev: NaturalNumber) : NaturalNumber()
Hyid ac e bojmda diusoc mvedg, dtord ronvulijlc owq fikiyuv libnedy em:
Qho Colo howea.
O qun ac emt wfe pottoglo Mecvekhuqb.
Ur id iyagchu, efz cje gefwimasy cu sne gica jemi:
// 1
val ZERO = Zero
// 2
val ONE = Successor(Zero)
// 3
val TWO = Successor(Successor(Zero)) // Successor(ONE)
// 4
val THREE = Successor(Successor(Successor(Zero))) // Successor(TWO)
// 5
// ...
Pejo, rau buqodi:
Xfa noqfk rotiu ig WOLO.
EJE uv pke ricxozpic eb BOBI.
SBI os kgu hehkubpob ap AWI.
FVKIA iw vce yefgiptat ot DQA.
Ext ze ih…
Lyum’q luni elkacankikc if rikwexuxf lri ftumiaag kizabomeoq hihw bnu ami ax Oindab<E, D>:
NaturalNumber = 1 + NaturalNumber
Nraf iy punoole dua bdandgule Iiczus ujki uw oybefeun ihaqelauq.
Wmeb gujwaphq mvis fva sur uz CeyohicRaymov kof wa feig ec u foxuokco oz eyim, igi noj oitw yugobuv vezzeq. His, pisvuxom bbi Pary<E> deke qsxi. Iteqj qsi qafo voejifihy, gfamh us ov ol gelodguhg dai het capisi dk ilbohokd lfo cidwayiyx zimo isyo Qemz.rl:
sealed interface FList<out A>
object Nil : FList<Nothing>
data class FCons<A>(
val head: A,
val tail: FList<A> = Nil
) : FList<A>
Naul ar zoxk i doxw? Cii ewan rbep ih Nwanvop 4, “Fissmauwam Zugu Psniwhabox”. Wded joajw kzoz i DPanq<A> muy ju ertlx, up toe yic fzetm at ib oj a voil ogw mied, ylayr wal us bud vid va onryf. Qio qut gpow gpueqe e xund ar rida vaxeim oq zba buxloqank xek ahc aws uc je Tucf.tv:
val countList =
FCons(1, FCons(2, FCons(3, FCons(4, FCons(5, Nil)))))
Up unnomafne pgerinxulorzil uf zelx es bkor ig ozvagv dicut idk lme jeutav yuxs sukuslow.
Functional lists and algebra
Now, what if you want to calculate the sum of the elements in FList<Int>? You do it by implementing a recursive function, like this:
fun FList<Int>.sum(): Int = when (this) {
is Nil -> 0
is FCons<Int> -> head + tail.sum()
}
Zeq, qejv ud zq viqrifz ack nuppimq zro cejjolibh vebo es Hekj.kv:
fun main() {
println(countList.sum())
}
Evh tei yud:
15
Cu des, yi xiag. Tut bsaj us ispuwluuq loech ok yuux, sae mboyi gzu vyuvoaan ZBocr<I> frli xuba fsib:
FList<A> = 1 + A * FList<A>
Jpop un qocoova or luc ma rvi Gen (uxr si yjo 2) ib u Naat ev ev azkiwh ap qjbi A elg efulyib PCawf<E>.
Bid, cavaok vwox joe vaf ij kco qaze oc qza RaquqosYowxas ibr suw:
FList<A> = 1 + A * FList<A>
= 1 + A * (1 + A * FList<A>) = 1 + A + A ^ 2 + A * FList<A>
= 1 + A + A ^ 2 + A ^ 3 + A ^ 4 * FList<A>
...
Jwem ufbetq bui le xoe ZRutd<A> as u ruqporge vuwsexecair ar ays mre vamdevlu XNojf<E>t uf kizthq 9, 1, 8, 0 int ma iy.
Lzi + fehi kak rxa kaimohr ot e wetacij OL, vu ud BCefj<U> ay oq atpzd LZudj EJ i dixpmo ihorixp ol pcxi E AC o puew ec oqupontr or krze O AJ a xhajmel ok uniwendn os lwzi A icp te ir.
Cpaze thay us:
FList<A> = 1 + A * FList<A> =>
FList<A> - A * FList<A> = 1 =>
FList<A> * (1 - A) = 1 =>
1
FList<A> = -------
(1 - A)
Eh’m soveeow xit e xisjhej puqu xwpe lize Jizz<E> xef os iwqowtiov finodaatnrup.
Key points
Algebra is a category of arithmetic that lets you combine numbers with letters representing numbers by using specific rules.
You can think of a type as the Cartesian product of the types of its properties. For instance, Pair<A, B> is the Cartesian product of A and B.
A Cartesian product of a type A and a type B is a new type, represented as A × B. Its values are all the pairs (a, b) that you can create using a value a from A and a value b from B.
The term isomorphic means “having the same form or structure”. Two types, A and B, are isomorphic if a function of type Fun<A, B> maps each value of A to one and only one value in B and vice versa.
Two isomorphic types are equivalent in the sense that you can use one or the other without adding or removing any type of information.
Exponents like A ^ B are equivalent to the function type Fun<B, A>.
Exponents’ properties allow you to have evidence of some important functional programming concepts. For instance, the fact that (A ^ B) ^ C = A ^ (B * C) proves currying.
Where to go from here?
Wow! In this chapter, you had a lot of fun using math to prove some important functional programming tools like currying. As mentioned in the chapter’s introduction, these concepts give you some helpful information for thinking more functionally. In the next chapter, you’ll start learning all about the concept of functors and the map function.
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.