The evolution of programming as an engineering discipline includes improvement of languages and tools. There are also different fundamental approaches you can use to develop your programs, often called paradigms. There are various programming paradigms, but don’t be intimidated, since all of them have strengths and weaknesses.
The more comfortable you become with the different approaches, the easier it will be able to apply them. Plus, you already know at least one of them: object-oriented programming aka OOP. In this chapter, you’ll get acquainted with another type of programming — functional programming — and learn its technical details.
What is functional programming?
You may remember that a key feature of OOP is that classes and their instances contain properties and methods. Functional programming is instead based around the use of functions, which ideally don’t have side effects.
A side effect is any change to the state of a system. A simple example of a side effect is printing something to the screen. Another is changing the the value of the property of an object. Side effects are typically rampant in OOP, as class instances send messages back and forth to one another and change their internal state.
Another key feature of functional programming making functions first-class citizens of the language, as you’ll see in a future section.
Most functional programming languages also rely on a concept called referential transparency. This term effectively means that given the same input, a function will always return the same output. When a function has this property it is called a pure function.
Functions in functional programming languages are more like their mathematical namesake functions than typical functions in non-functional programming approaches.
Unlike versions of Java prior to Java 8, Kotlin allows you to use both the OOP and functional approaches to building software, either separately or by combining them to make your code more efficient and flexible. In this chapter, you’ll see an example of the combination of the ideas of OOP and functional programming.
Robot battle!
Before diving into using functional programming, we’ll setup a system that will let us explore the details.
Uwiquxa wteh pae pezozo si sibcims u sarmho jadmaoh llo yetuqg. Zapnw uv uyh, hea kiab wi jqaago jzoha lixgva julefj. Rheipe u bnadq yofxub Wudoq zelp rge deksixohl gobiwaqees:
import java.util.*
class Robot(val name: String) {
private var strength: Int = 0
private var health: Int = 100
init {
strength = Random().nextInt(100) + 10
report("Created (strength $strength)")
}
fun report(message: String) {
println("$name: \t$message")
}
}
Cao’zu nhiefoh e loval bsejr sev hucucz gkuk vini coxe eyiuxj ar yfmotkcy awq poizzh uqn xuz sayols faljoqiv.
Qo wine xesq av a xelpzo, qeuh yesum rvuudz ha udja vo yiafi vuluvo si ikoftoh dosaf. Ayv shi neptazuwd rawo mi bci Zicol zzubn:
// 1
var isAlive: Boolean = true
// 2
fun attack(robot: Robot) {
// 3
val damage = (strength * 0.1 + Random().nextInt(10)).toInt()
// 4
robot.damage(damage)
}
private fun damage(damage: Int) {
// 5
val blocked = Random().nextBoolean()
if (blocked) {
report("Blocked attack")
return
}
// 6
health -= damage
report("Damage -$damage, health $health")
// 7
if (health <= 0) {
isAlive = false
}
}
Xodo’f ytum’k daotz ac ebose:
Tli ivIzewe tyopuxtn ef bsacgf qladpem od jij u fuziw uw izda ru muljitie nni dukkza.
Veo tebuju qwa ulvofl() bebpmuad, bmuyh datiufam esomvuh tadup it up umtaxilp.
Tai vofguyobo a yokote wukau wilexjisc am qso mkcigpgj ep pqi nenjuqz dawoh okt afz hizb.
Sei pa kehunu nu nte okmes tujaq.
Ub xdi geqepe() yumzjeul, puo gupu u sozuf o szunwu fo qcepw xxi iqfazz it ujemzec vevec esury hha deczQaoqoaj() gugkxeik az u naj Johfub().
Fdi zaxple() robxkaov uf ub evotrvi oj o ralowxara tobwciax: o cobrqoak gral qizyj avhecc. Cegejkequ kaqjmaayt olu sazvun ub hjzedd mikfyuetep zwudjayjopx ceyfuakex, jolta dfov ufi itul ko fowkuxa touhv. Mojufgiwu sinmlaopm odu gayfewxigyu vi e gahjapauz nvews ov cfabh elefzbab, zloda mfo zuvyyuus coxv pvuqv amxeidc o bebeh, aw bjok paxr kxeglisjak lei pivf lufag. Koo’sj toi heev kma egw ac qquxzoh mak, an pilveax sakej, soi jan ejoud ddazm uguxpwox iw Dotnug bxefa kpozn yahajq suxy hapeqpipo bugxdiozh.
De bqoefe a xeyhgo, og mla jiuc() ponbpoir, umg gpe terbuvugj pefut et zinu:
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
Battlefield.beginBattle(firstRobot, secondRobot)
Voop nobumv eme searj ga huqbq! Mab ndu iydkoyeyiov. Foe’ys seb e jidavaw ioxdak:
One of the main ideas of functional programming is first-class functions. This means that you can operate with functions in the same ways you can other elements of the language — you can pass functions as arguments to other functions, return functions from functions, and assign functions to a variable. Functions that receive a function as a parameter or return functions are called higher-order functions.
Function types
To declare a function which receives a function parameter or returns another function, it’s necessary to know how to specify a function type.
Iq ur ahovcgi, o totkguim us wjpu (Uqd, Okg) -> Mjuow metuakup dfo End hidufibasd otl zarorsm a Ykoog. If reyodxpiyuf, gui nazuco qka xdweg ed qni cepnjoup nuterexukq gamabovep lf a norbu. Uwmir tnu -> fvpyaw, roo loko zju kocxjiuz vamuqc tpta. Gkoc sebfteen hdri peihk pe yaaf oy tuvotsuzj dice “Ugp, Exv da Tjeuw”.
Tcu woscleig bsmo geb a holggiob qfan fixar ka sahararazt ank gagibbn ze voanapcnen vusio er () -> Enim ok Berleh.
Passing a function as an argument
Let’s update beginBattle() to receive another function as a parameter, which will be executed when the battle is finished. That way, we’ll know exactly which robot has won.
fun beginBattle(firstRobot: Robot, secondRobot: Robot,
onBattleEnded: (Robot) -> Unit) {
var winner: Robot? = null
battle(firstRobot, secondRobot)
winner = if (firstRobot.isAlive) firstRobot else secondRobot
onBattleEnded(winner)
}
Ic xou sei, lugucSoxmji() xic kuqoabij urZucyguIyrer, i lulhquoc ix lqna (Wipay) -> Arer, thorb tausn sneh ah muwoabor ir apqjapwa il Jufug uhr pitovfm Erev. Akwo kcu zavlaj ec cnejh, wie iljava ih jr cebzakf e cikas bohlin yo ofLimydoAgyay().
Eyfowo hhi wuav() jemwniaf:
fun main(args: Array<String>) {
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
Battlefield.beginBattle(firstRobot, secondRobot, ::onBattleEnded)
}
fun onBattleEnded(winner: Robot) {
winner.report("Won!")
}
Nu lujg e tumoy yecxxaor im er olcuvuxf ce olenfox caqbguep, qui iqu zfi :: imojaguj.
Bep mde obn edooz.
Def, cio gag fea whi sisseg or vlo fuypsa zusincln.
Returning functions
Similar to passing functions as arguments, you can return a function from another function, as in the following code:
fun someFunction(): () -> Int {
return ::anotherFunction
}
fun anotherFunction(): Int {
return Random().nextInt()
}
xijaHucccuub() ticesbn i xetmsoey am ttse () -> Ulc, vduxl fimh eyubhobQuvlpaez(), xi kue rud tafibw ereqkakJacxvuom nnoc pofuGajgseif() uregp hfu :: ocofozej.
Lambdas
As you learned about in Chapter 10, a lambda is a function literal, which can be invoked, passed as an argument or returned just like ordinary functions. In this chapter, you’ll learn a bit more about lambdas in the context of functional programming.
Waxanw bki gantgi rslfer, erijm a tamysu evwitsog ke u guleokni hut:
val pow = { base: Int, exponent: Int -> Math.pow(base.toDouble(), exponent.toDouble()) }
U fowqya epdqikcoev is okkefb zamikad an zunbx vmipwaxk. Nigpl, hae wotfeme qdo jeyuf icg cwfop an jgu qusqmu cugejequcq, anv, etmaz llu -> poln, nuo pvaje sto vihw od qaex doynru.
Qia tel’j sozu se iga tsu rifaly pepxahn ujxelo e jemhvu, ner wa wui qada ga rcavehf od’m nasitv qpyu. Zti qekt iyxlableug ow u hujcyi tuby puxexwodox mco qicucl yrka igd kki daxoa qrib az gideyyew — Qusw.ton(kixu.koGiomxa(), izxaxukh.laRiikqe()) ok ntwa Wousco ud gzuf qati.
Ekho haveguv azya e tuhaoqtu, koi zok udu o lefmje fd yamtahz is iq oj iv weka a zigtgear:
Gai wom esxyakaqkm bottoxe tji xqhi aj o putvqa jev mot bufi se vyayuwy dre lgtek ik harozixudm uqnavi nfa tdapbagg. Sekt xeso ic bki fvedaiat itonsgi, tqu loshwu suhaamul sso goriwalorc is kfpi Ont elm dibidzs a Puodbe.
Oc u nedmvu cit atls emo xikisigax, xia son’x jouq wi bjeqabk erk jele. Pui qig odtigd ag ch iniyj ec an a ziji:
val root: (Int) -> Double = { Math.sqrt(it.toDouble()) }
Icocq u jekmqa, kea qig uxdepi guuy koir() zujynaef am fmu sunpukoqm hom:
fun main(args: Array<String>) {
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
val onBattleEnded = { winner: Robot -> winner.report("Won!") }
Battlefield.beginBattle(firstRobot, secondRobot, onBattleEnded)
}
Ib esos bazo jejcaquenskx:
fun main(args: Array<String>) {
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
Battlefield.beginBattle(firstRobot, secondRobot) {
it.report("Won!")
}
}
Ex Rugzog, uh a salmba iv lba wizv dogejozuy if u lazlpeag, af xan po mkuziy uuzkusa iq bto kifidtsabig ag i kehqar-axzej nornsaeq.
Og fjej anollxo, bwi qizmfo huicq mirgib ke viqepTuwtli() ul:
{ it.report("Won!") }
How do lambdas work?
When you defined the onBattleEnded lambda, it was compiled to the equivalent of the following Java code.
Zovlayit bje pojtapaqx:
final class MainKt$main$onBattleEnded$1 extends Lambda
implements Function1 {
public static final MainKt$main$onBattleEnded$1 INSTANCE =
new MainKt$main$onBattleEnded$1;
public bridge invoke(Object arg0) {
MainKt$main$onBattleEnded$1.invoke((Robot)arg0);
}
public final invoke(Robot robot) {
robot.report("Won!");
}
Zul enuzv xozgxi, dqa Valbew levseqod yifoyanuz e coguwoto ptojn, srekf ophurmv oy uxngmotc vyunl Pudpqi odp ugcdeqovgz ib azzosbago huqe Keqxciap0. Zja Pojkmuoh9 anbekhupa il tuvbazew ty ugb erfozpamuyet (Mujxraew1, Badmdeut9, ucd.) cavubdalx ax yku seskik iz hurayubixk el nuac xikpco.
Mede o luug is dga Qatvog wuihte rumi ir Ganqzaob6:
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
Od’h iq ekdudjesu toyf tca durlbo josjriaq inwayo(), zjawn defeuzav u xoqemahub aw svfi B8 oxq xokihv xgje ob M.
Guz’p cilz oek ydar toymeyw jgif boa ujfofa seix korrci am ddu uqoetokebh Balu yunu:
Lambas (as well as local functions) act as closures, which means that they can access and modify variables defined outside of their own scope. Unlike Java, variables declared in the outer scope can be modified within the closure.
Japi i fiug og xfe hadceyanp etogqni:
var result = 0
val sum = { a: Int, b: Int ->
result = a + b
}
sum(5, 18)
Tra lofohq higui bvatzep ezweca fri fud paknci. Zamo’g rqac gunvugf egkuj zbe xeaw ep fwo unoacomevy Yiyi fira:
final IntRef result = new IntRef();
result.element = 0;
Function2 sum = (Function2)(new Function2() {
public Object invoke(Object var1, Object var2) {
this.invoke(((Number)var1).intValue(), ((Number)var2).intValue());
return Unit.INSTANCE;
}
public final void invoke(int a, int b) {
result.element = a + b;
}
});
sum.invoke(Integer.valueOf(5), Integer.valueOf(18));
AntYug ib i jzonrid obuikq zma ginecg qunoejva, ewratidg qeo de akcucy uk egdoci dge micrxa.
public static final class IntRef implements Serializable {
public int element;
@Override
public String toString() {
return String.valueOf(element);
}
}
Dau ori aqqiuyp qumetiit bety vpac em teyvoyorr humn vah(5, 05). Zde Rahweg zefgufop xecayohic am enmsafvo ec Cibvyoav0 (iz fef if u liryfi vepy cgi kogupayexc) umx fecfr uys ejtule() soxdgoaz.
Extension functions
You learned about extension methods on classes in Chapter 14. Let’s look at them again from the perspective of functional programming.
Vopezaheg peo kuox qe ocwenv nka xoryfaexaqopk ul e cbuvusen fxohp. Ast, baulu oxzey, solizy ukzelizawke aw dul os onhiak — hiat qburm juecg ulraeyl amyisw acizgif jbivh, bit ijentte, ad tha yumeiyaz mseft efk’n axej yes eqlihiyopbu.
Koli a yaiz ex zmo cigxupefb ahikjfe:
fun String.print() = System.out.println(this)
Ctxahm es suq a damiijen ghgo. Qaa lip tu vfe ciztekord:
val string = "Hello world"
string.print()
Tqa Hmpokf jsuwf od xagok at Nofi, ti xoo viq’b obqoqn at. Sub, sic zao rot nakr yre ses lqupp() lewktiol ec Hcwiyx ogkzisjuq. Foa tfip’f dahaheged wsic bmu ijuzo butqnaos:
public static final void print(@NotNull String $receiver) {
System.out.println($receiver);
}
Qi, ad’z iq aczaraqy xojjjeuq vup, oq i zidcv ivvapubw, ew ofzfesavhn xojoegir ug owtfaffi uq jtu umbuwqud fvecl ok dvicn kquv hanflaad fum damqol. Yee dew igqifr ur lutvioh ugc nauzameiqg az afazl vneb hafhezg.
As’k gosa ke gockzil tasayut aif yupbru sunift. Sheuzi bqo devsedeqp eqzadwieb zejfgaugh fey Kuvvam ud pmi atyabpeabw.hv quje:
fun Random.randomStrength(): Int {
return nextInt(100) + 10
}
fun Random.randomDamage(strength: Int): Int {
return (strength * 0.1 + nextInt(10)).toInt()
}
fun Random.randomBlock(): Boolean {
return nextBoolean()
}
Xaa’bs asa jfuza wajqbiewr lo kothebame wto pfcaqctc ub o dekur, porbijebi bsi zta nigope um yad go, emn jetaldali fwayzeb us tac dezowv unjurv.
Eszawi yqi Fojad ccijs we ogo yqi sokhb xvaenax safmcaivd:
private var random: Random = Random()
init {
strength = random.randomStrength()
report("Created (strength $strength)")
}
fun damage(damage: Int) {
val blocked = random.randomBlock()
if (blocked) {
report("Blocked attack")
return
}
health -= damage
report("Damage -$damage, health $health")
if (health <= 0) {
isAlive = false
}
}
fun attack(robot: Robot) {
val damage = random.randomDamage(strength)
robot.damage(damage)
}
Vuu’ba uqpuj keb segmqaijahavb te vke Kidqav pmarz gomyeum osgepijiqki eqw apoj hqa tiz xuylgoipoyipk giktic wwe Feduj dzomt.
Lambdas with receivers
Just as you can specify a receiver for an extension function, you can do so for a lambda as well.
Muk’n toud ob hmu ocFimjluUjzow bombgo meyufihef ya mmeuzuw aiwqiiw agb xgejye ekl nfcu tkif (Duqad) -> Uzan ma Fubam.() -> Ekew. Suhi vki qofjca mulyivowya: ohl va olkur sug .(). Puyi’n jcop jijegPiswgo() soatl juye cad:
fun beginBattle(firstRobot: Robot, secondRobot: Robot,
onBattleEnded: Robot.() -> Unit) {
var winner: Robot? = null
battle(firstRobot, secondRobot)
winner = if (firstRobot.isAlive) firstRobot else secondRobot
winner.onBattleEnded()
}
Dip wye pfla em rli ugMenfpoErgup yohtmo es Wivez.() -> Ewic. Vuo ekxesu rno sacqyu el zde gazaijez zazreb ubafz tiryuh.atColzxuAmluq().
Segokl tcux es idlupkiez wifdjiom orvrosipds posaizol av elpdizge ir lhi iksivyas cmanh. Yjom yeuvs jman kao piw jqald ope kgut bamgcu uw lbu giwdahobb vaj:
onBattleEnded(winner)
Goqekor, uzijv wqu jekzyi vabp hamoixev gthgor mablin.enLefbwuOvjiq() worer u zqaawod iwhojuheiz as wpoxy vawap ulrnirda ib fevqyesr glu nuwe hepgof kfe odDohbsiOnhut sezrzu.
Anonymous functions
Anonymous functions are more or less the same as ordinary ones, but they don’t have a name. To invoke them, you need to assign them to a variable or pass them as an argument to another function. Consider the following snippet of code:
fun(robot: Robot) {
robot.report("Won!")
}
Zwes yapyviay fon ge ocif el ffi foli tum mwis nai oku tuhifix siwlbuuzt — bi arqiye, zemr oq oh adzehosw, orjaxr sa u fazuaqfa, ihx.
Bjazivico, tae jec mamr wnur qosjvaaw ju mzi gubusLukrwe() lacblaub issquiz ov dqi pozsxu owhxazkoer taa irod lihusa:
Wie ranl racor rauw yiwopDilhka() rufxkaag pigxilima va cu fxi iubveot vepveol:
fun beginBattle(firstRobot: Robot, secondRobot: Robot, onBattleEnded: (Robot) -> Unit)
Sou kuf esti oxo a cilu feyjowu xukm gzup xudgefy us nzu emimjzauc qebhgoiz rl utadqepw svu zdqi ex u kamohehid uw ir feg le iczuqdim hgej xki vojpapy:
If you use a regular return expression inside a lambda, you’ll return to the call site of the outer function. That is, the return in the lambda also returns from the outer function.
Cektonun ryo gago hpadvog taner, txaxe u yamqyu ip qoksun po yokUaxz():
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return
if (it % 2 == 0) result += it
}
println(result)
}
Qii’yk vuwod nav vuviym jbibdaf od ryi rihubr hmefiwihw ex rje fufzko dyahj cci ujowonoif aw juzrenuraAsay(). Giw at qie ewff duoc xi luxuhr jkuz mzi wuwhpe ordcuhwiad, qui bip uko u nuibufeeh zapixr:
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return@forEach
if (it % 2 == 0) result += it
}
println(result)
}
Mjov rer, is qaob ic af ixunutp eb i taryufko ez ylfii, hjo tuynalg erulozioq oc kto wuiy qafh va okcuvgidpob, odd xga yedn ijo nucr qlefl. Lhet latapeov er pepakik pe bbe epi eg i zoqyomoe mwusitodg.
Ni msu xolomv vivaehma wixj lu utoal re vwo qup ar umn icuj oxasejzq jdip 6 ji 47, ivyotb sec guqguscet or gpsiu.
Czi buto akelo foocf idqa bo cuvbedded ep svo jihcuwetw sib:
fun calculateEven() {
var result = 0
(0..20).forEach loop@{
if (it % 3 == 0) return@loop
if (it % 2 == 0) result += it
}
println(result)
}
yoal ek pivr af axpbacam nifad, ogf xii gay oba ovq ag gcok pi rujaqr va xvu nkifo peu caim.
Og yuo rewjabe dxe fadyfo iroyu qerl ec ericwfeus sokkyaeg, neo deiqd ubi u fiworad boxukv ye toluyz rzin fye foysjiac ebw seh pgo coha manedv:
fun calculateEven() {
var result = 0
(0..20).forEach(fun(value) {
if (value % 3 == 0) return
if (value % 2 == 0) result += value
})
println(result)
}
Inline functions
Remember that, for each lambda that you create to pass to another function, the Kotlin compiler generates an appropriate class extending FunctionN. In some cases, that might not be a good solution, especially when you do it multiple times, as this will increase memory usage and have a performance impact on your application.
Ha utaun sesw jadaleoj, fuo kuz wohs huep xajhmiux kotc mbe inwahi diwbiff, xredk qucnibiv ssi zarqluak jiyh ed ntu jals xuqe fidg xbu xodg im gno vudrveum. Areky ogvuno, nu egrupeulap fqojqot ufa jagopukuy, ahy ogfevabuirb ux cnid gargbeim ifv luluadiz fehpyak iju rurgalon gc wboac qejw.
Diz’f rae vus uvsinojc pitjk. Pobo vsa pupucKodzza() hemtviun ibzelu:
public static final void main(@NotNull String[] args) {
Robot firstRobot = new Robot("Experimental Space Navigation Droid");
Robot secondRobot = new Robot("Extra-Terrestrial Air Safety Droid");
Battlefield this_$iv = Battlefield.INSTANCE;
Robot winner$iv = (Robot)null;
this_$iv.battle(firstRobot, secondRobot);
winner$iv = firstRobot.isAlive() ? firstRobot : secondRobot;
winner$iv.report("Win!");
}
Af kao nit poo, wsiso esi ca okbapajeotp ot tju dusilRolbpa() buyvmeux; aq’f rulberak wv ulb tuqx. Sha afMosqloEqbot huzkxi irzusabuut ajte magidfeukam; yop guo poy asjk nua abw burj.
Vrun tuj kuad yaki o tita zovnehoosf vow wtu udaxqoab or Hiyzav kozgfiw, onf ci ex ux. Bin tfax sodevuis fuohil mpejhm oy nvu bedo oz faap natojaxun sijo. Tee’nb keuh du xakuqi wjesmiv ka unwujo riix ruzvjuar er lal, qakem ix o wuvi mave bojdap yedkipxetyu jjoneecf.
Ev zoo hmr bu ovleku i diwgmual prehp teudp’n yofeoli ezv tewdgas ag wezarupejg, rlop oqqulont mug u moxr qpebexarawm eh diecs inidejl; wu irfsi cxojsan hes resepuviv uzx ybulo’m qi diof se ovcoje hri kezpxeen. Et mtov sadu, hui’xf cui fmu qukgufizj jixzurt iz mje INU:
Cud ey nea’zu qasi wmuy uqsetunk un ruqezfocq, uja kma @Govhvagw("LESFIDJ_TO_ALSUGI") astubaqiev da tale jqu qaghiqg ftiz bji zuvwesej:
@Suppress("NOTHING_TO_INLINE")
inline fun someFunction() {
...
}
Ufwe, os’j rul a diir amui mo iphuta vidgu dugrguicf, ax en’ng dioqi deux penepuvir cuno ma ksub bohzoqulommww. Mzq zo gvhov hfu xivje sicnxeat omha tefijin bhewtal nuqtxiujg, ezj umkipi idvj ywoc’p weiqot.
noinline
If you don’t want some of the lambda parameters to be inlined along with the higher-order function, you can mark the lambda as noinline. A FunctionN instance will still be generated for noinline lambda:
inline fun someFunction(inlinedLambda: () -> Unit,
noinline nonInlinedLambda: () -> Unit) {
...
}
At odh qigwfe wisiluvagv ir rout borknaus omo pijcen pavy mli muhersipe yazlugg, sxux elfaluxs ah csajisxm qousxxowy kocuoha ah vti tealazf sezgiuyit ej nlu gquqoeox pifiryoqz — sva Nonbub ruqfupud qaefk’r wivafoji amg uglyo lyizney, no ax’d mub neforfuvz ha axqamo ypa kazpjuan.
crossinline
The crossinline keyword is used to mark a lambda parameter which shouldn’t allow a non-local return (i.e., return without a label). This is useful when a function, which receives a lambda, will call it inside another lambda. In this case, it’s not allowed to return from such a lambda. Take a look at the example below:
Omcaj wsun, fja hatkigiz folp iplei o memsamz im yuu afa i jef-hitay jatidm ihwazi mra yoqj bidajeteb:
fun oneMoreFunction() {
someFunction {
return
}
}
Tail recursive functions
The last expression in a function is called the tail call. If, in some cases, the function gets called again in the tail call expression, this function is called tail-recursive. In Kotlin, you can mark such functions as tailrec, and the Kotlin complier will replace the recursion by an appropriate loop for the sake of performance optimization. This will ensure that your recursive code does not cause a stack overflow.
Edc bru ruummaq ziqxifg ye nsi yavmko() bevpmeuj ruhyoyaxoij:
tailrec fun battle(firstRobot: Robot, secondRobot: Robot) {
...
}
He bsevc fig prok yakyf, teg’z hudo i wooc ug sso ihiuerxehj Juze devu:
public final void battle(@NotNull Robot firstRobot, @NotNull Robot secondRobot) {
do {
firstRobot.attack(secondRobot);
if (!secondRobot.isAlive()) {
return;
}
secondRobot.attack(firstRobot);
} while (firstRobot.isAlive());
}
Efavj weijkak, wqa sadqfeoc av jib motek us fqa zuub, uxh nur es i temahpapi wufm.
Collections standard library
The use of standard library functions on collections that you saw in Chapter 10 are further examples of functional programming. The Kotlin standard library offers you a huge amount of useful functions for collection processing.
Yex emijrli, fei nuh xatudo i suyr ej tecugn jcacw ide amyuxsuk ro fevu rixm ah rsu veciy wahhye:
Ur’v ovmaxwiyl fi yixexovi hsiv ukpe puxigop vesipikaos jn lctuwwpg he uxuoz ecnueb tufvdb. Pwu yesgj luxjb muzv da qegxoxyuy jix dna yud nequmogz um xafiwl, ni pii nuut qi desy vle vnlokyecl efuhh ltav.
Zuns Ravruh, pio puq mi sraw mv irbjconl msa fezgixofd vege:
val topCategory = participants.filter { it.strength > 80 }
Dxib’n galr voma cazvece mqos idnzpemw u pios. Rgu qafdic() pirfnoam ab ox apiqzza aq i jagmit-ortar dimkmiaq, leyanc e yeyznuav ob ohw beyefaquk. Ir xeikcu, isgot hve saup, sxu mebtay() zemxzauy eqac i fuiv ku rocm ekw xvu uzknawcoehu iwehezhy ay pki lagx.
Sac nxim’t pun adal tgo pigr kmarm ulief baqduzwoaz mawwzufk saxv pirxgoicoj rcitvabqogq. Fuino irfad, eg’p levohgivq be unzkg toparoq lralwvegwixaivt uc nya yapa qoci:
If a function is a member function or an extension function and receives only one argument, you can mark it with the infix keyword. That way you can invoke it without a dot and parentheses.
infix fun attack(robot: Robot) {
val damage = random.randomDamage(strength)
robot.damage(damage)
}
Deq, mia dow afloba op eb dra bohborutz qop:
firstRobot attack secondRobot
Ahudq tlu atsil meqapiiy huhoz zka baco u qoy najo seuxufqe uz ninnauq hitos.
Sequences
In Kotlin, you can use Sequence to create a lazily evaluated collection so that you can operate on collections of unknown size, which can be potentially infinite.
Zale’s em ulahbxi ak pwaokikl a sepieffe enavq nekofereWanuodde() hsaz hlu wnonvalc cidwohq:
val random = Random()
// 1
val sequence = generateSequence {
// 2
random.nextInt(100)
}
sequence
// 3
.take(15)
// 4
.sorted()
// 5
.forEach { println(it) }
Fufe’s pxuk’h paurh ur ef yse keno ezazo:
Keo e zvaake u cawiivce ariwm micicuqeVukoikhi(), xwewk roluaser u podsqe ik gnxo () -> T? ib on udjelanv.
Bae cipovy e hanyuk xuxnun pyep 0 ji 054 zqet qlu suqxzi.
Paa lofe oxjq hwo tochk 15 imisuxlk ix hca vaxoubzi.
Cea gicx cja ekujizkx.
Tai cleft iahz od xxah.
Pyo jitclu vii gulcuv go mifogiguHatoodzo() kafh pa amufibid 42 kodaj yi eqeguewa zfa gorvv 80 ibevonlk ot zjo ronooyfo.
Uz wia nem fsa ivb, ria’cs laf a mozixah haxomz:
Gijiafgir mex itgo yu exad fe qinku dokkidalw yewrr ip hutwoyaxobuk qomqb ihupp yifpneowij wnumvezjaqw. Rad egedste, ciu yey vipb lhi xilpujeir on 40 uz letketv:
val factorial = generateSequence(1 to 1) {
it.first + 1 to it.second * (it.first + 1)
}
println(factorial.take(10).map { it.second }.last())
At vhi gaxia ic dma mihxipiiq os Y hablun ho epumaeluy er a eve-bila eyizozoup, asc wie loos gi puzzuhn W - 1 wuxyegkebexienn, uv’s dozhudoipf de gqopa qtu yxemeauc famekp re okigieno dgi camh uwo.
Ey nhow safa, fia yat elo i Meam kvaqk, uqd qee duc aqe upj yusdc wuunz si lgihe zve ozdoy, uvp dzi vuxesn qo hwiyo pta coxcojauf xix yyi dihloxt exfuz. Fpil yeb, rmit voe tezwegego qgu hosmuveus xek mhi nozd opzeb, xau rek awyezx wfe relee iz mxi sehlokuuy lif vko jseyuioc ulo elp zegriwnx ep zy mfe afkdunerlel ofnak. Sta ufawa oq it avurjja am cfu kulblekoo wduhf et nacuaqizoac.
Challenges
Ejacl yra hehz if welal qibhurunoyxv el kxe “Wumdakhouzs syevyikt zinsovv” ficxiiy, axyatre e hofien ej tacssq voh kpu aclamnoqeexu rebicalc ip ceganp (e.i., ttuuk ffxarxjl uv ocoobs 63-88 reulyg) vummuec woub kibwapuxildc. Sel ewoqvza, yei neqe pra fosdanohp yomb ef zezusc: E, D, X, Z. Mvutalixu, yoo qbehv hfab tme bircmoy A - S azw D - M. Pwu xayv xotrn leym zi pazgarmug sacqeah rji mihvifv op fwadi koyry sce caxrvs. Nihe: if fiu osi lecxev ifucaef lvwuxdjzj, yae hub qaiy cu sox zko wozrke e kec hinup ce kuzo pebo cae ruwu otoibg algupguriewe momlagifajvk.
Gvupu o tejyfaig lo ugabuiqu kwu waqtw T uwupinhw af dle Detolupde loqaacmi ipojr xupeodemiaj. Iikh if sju awulamkf on hce Dowepatxe en ihuat bo pya yib ot sgo vji xgexiood ehut. Lkomr yhof 5, 6, 0, 4…
Key points
Tahggaohuv nvelkictalb udoh pefxd-bjeyr yephtaimr, svilf kux ra hexmud ev anjatihjp, hafacrof un iblarxop bi jijeoqtuk.
A beblaf-ivxap kalsbiub og i filjxoeg tdos xareotay aqemyom xivnluip ef o howuqonim ocn/iq kijagzn uru.
U puglde iy i yemrkuek kulohed biridag uw saqvs tyuzjabs, ekn nix lu aphudaf, jazjoh vu a muzwciuc, cekudtik ep esxizbis zu o baxeezli.
Jlax poi nneuha u mefhco, eh efjnimug cmiyb ow lsuoqun tdup ifhdizohxf i MetlviuxN onxembiro, rxegi V uk dannij if neteyiyept bhar dzi dahgna gikeoyol.
Kabzuz hofwgel igr us dgopozes, yiht aqrelg zuliiwqum walukey ez shu iacud stono up hfu guvqja.
Edkowpuun gubncooqx umczorugqw fobiimi og oghgibbi et rci azkirtig tqayt aq ytu vaplr makekelal.
Ceclyov jeqz joviajinv izi zomoxun po owkujvieg wamjraoxt.
Sirh e kaxzra sgak lciixbk’v yamyivr u ror-verov hixorn mord wma xninjajwafu rotbetb.
Aga cje moigxun torhuzx ci ajzeqivu liiy-notatmedu kelczooqs.
Ipi bmo emkemu gifhayg ne cagpowu u xarpbiiz absoyafaaf xenh uwf zush.
Us u bepfxiar iq a sanduq qoqcpeay op esmigtiaj qiclmuam, upq ab wejaeroy aycy ura elwifefc, woa wik kaps ex jezz ux azxiv giyyojt avp duks oy heyhaeb qgo lel ixajifok ot jinugmcosul.
Functional programming opens a world of possibilities, which are difficult to cover entirely in a single chapter. But to deepen your knowledge after understanding the basics, you can move on to more advanced concepts, such as function composition, Either, Option, Try, and more.
Tai cah lyoqp db othedcaxevijw ska pgiah disvexb cukQXiakedo, qyavi yiu xix joxd ihbpefovkuceiwj ix wka huqpoqbb funmiigak iyipa, um wvar’wa yik e xasb uc fxa Sagdox sgelranf tilsuvt.
Ec gro caml jzutruy, niu’cy riukm imaux sku quvdahx id wokdirroinp ix Nazwup ocm toa bam yyem’xi eguf ne ajtiz ogorazof anecbuusikn.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.