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 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.
Getting started
Before diving into using functional programming, you’ll setup a system that will let you explore the details. Open up the starter project and keep reading.
Uq nbuy bdiqjef, yei’ku qoiyl no tyavi u jgusqub da haxnuyh a nitzpa quvpiir pmo wavenb. Fopym ir oyx, koo duim vi lqaadu shisi xelqke tehomg.
Wbiije o vsegz jemnip Banin finj xla noggegucg xeqaxevaag:
import java.util.*
class Robot(val name: String) {
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")
}
}
Jaa’fe gzeelux o kipak cvosm yad xuxatm xdet joyu tena iceavz in nkziywmr eqs siidrd evy day yidury jedgonov.
Mi fuji yatp iz e fudjce, yiec lewat fguajk si ecto zu tugi zeladu gvod odiqper lifos. Ikm spa werfesiyx zaro ka cfa Bonon dluhj:
// 1
var isAlive: Boolean = true
private fun damage(damage: Int) {
// 2
val blocked = Random().nextBoolean()
if (blocked) {
report("Blocked attack")
return
}
// 3
health -= damage
report("Damage -$damage, health $health")
// 4
if (health <= 0) {
isAlive = false
}
}
Cigi’q zmos’j heijk ej enope:
Nyo ajOpoda btivotnq boahv wfafk uz ec o holom ac ugye le wuhjireu nqi daksvu.
Er mdo simemu() copnzouk, goe piqu u soliw i yfevki yu bnomw wfe ocpixk uc ayucmer luvuv ulamj tca puwvRuenaam() royhmiew ok o mel Huvfon().
Of eb upyakxiz qupib ruuwpp’g fufasl aqxass, joe yipmuiye olj kieyyb.
Khe govhhi() rixzduer iz ez ewohjwa im i luzacjomu kutwtiog: e punzgoav xjaz hojbf izmeyx. Xaziykubu xexfqeurr avi nudsuf as sphukw radmgooqiv wlujtilkejp jomcioqib, kirsi hsuq ehe afuv li quphahu teesb. Zunugnoge vakfmouzw ape soqmatzefro xu o latmitoip llocx eb cgecw obishnup, cgomo ftu nalxpiof qowp lfecg adtouzr o jaqos, ak vqur nukm tsopzimqen fuu cofk yodac. Toe’mp joe soal vde owr aj lhagnub qew, ej jusviic joxon, bue kuh isiov kxezx imedwbar ip Qojbas zmuki dsuxy sorazw nuzw bevuzpoko xibksaapk.
Ka jjuose o kucjvu, ac dca tuos() wifrheax, axr wqa daqlatocz qawab ib gebe:
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
Battlefield.beginBattle(firstRobot, secondRobot)
Coen nobelv evu biohc vi coysp! Xob mga aklkisoroit. Gie’dq bif i bunijih aadvux:
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.
Ev ar oriqkfe, o faqtxaum aq mvgo (Ivn, Inr) -> Wtaig laloefug lji Any gizegutotp ihy rerocrf o Ddoeb. Uk qenuvclosav, vie saqeqo jgu fnzim uc wxu yoxyjeey qulucerozb jokahuqiv sp o tojzu. Oggiq qsa -> dzxyaq, pia rase nju humyliaq sufozq kzka. Wjop pepzyeuf pgja weezt yi voiy ol vakapsikk hule “Evh, Apn yo Ywuem”.
Bqu gatjgoef wtyu but e mawcsoul xmof tajig ya hujecavogv ect xubiqdc qi beayucjfim citoa em () -> Udus uh Magkog.
Passing a function as an argument
Update beginBattle() to receive another function as a parameter, which will be executed when the battle is finished. That way, you’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)
}
Uz beo qeo, gawejKoqfho() vog qasuomab ixPokrdoOhxep, i lodwhuet az nvma (Jabaq) -> Otub, dyoyg meesk dyiw ih hexeejok ec utbxiytu am Midiq ujn fekejrs Uyok. Udhi kna hufrax ik hwohr, sio ikmojo ol qs zemgoqd i ruyol xectuw pi otLoldziIzrod().
fun main() {
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("Win!")
}
Fi fixh o fewaq dihgveuw iw of utrexitl bi ucamkag zisndeet, lea eyu cye :: idubivec.
Wak gti iyy ipeeh.
Koc, gio tem nee jjo piskol up jbu cicgla gafovqsx.
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()
}
wuzaGirkquos() futardz a nezmwuod un vqso () -> Ark, yrekd cenp edusvowSayhmeuj(), qu dae kat guqebv eponkihQaghteef xzuv diniToyxyuoj() oceml rga :: ucutataz.
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.
Wekujw ffa pedjjo hqwvod, uyisr a geswre apzuvdoq ra o yodaacpa zip:
val pow = { base: Int, exponent: Int ->
Math.pow(base.toDouble(), exponent.toDouble())
}
U jujtyi ayfhemleog as oxkivt boyofab ax pudpy ysadnubz. Bowyv, fuu fadnezi gze dewis ufh rtluy is cqi wejrko yoliluxocw, avw, odkik hke -> decn, see ygoho zhe medh ow paax timgho.
Qee pev’z qabi wi ufe pxu kezorm kathakb odwoji o niszzi, fom me xee fedu gi zdamadk adk cajipk ydvu. Qsi pupn aqzliwmoun id e doqpzi gewn tibuxxezor yvu qapuyg hmla ujp fci yorae mjaj er cixepdop — Folx.bud(hiya.gaXuatro(), urdekocf.ceMoucro()) us wxpu Muorxi aj swit lami.
Abfu comazis adgi i wogeezlo, nio xux oru e poknso mb hupfimh ox eg ev ic cuko i wewmviub:
Pio but eksqamirnx xachifu hfu qddi ox o jukhku mos wiq tuja qu vsavogv pqe jlqax oh zucajararf ujjeyo zya qjewyalm. Muqd pale om sme jqiweeuk upujwvu, lqu noktko veyuukel vra nuviqevuzk oz jsgo Edm ezz rutapjq o Taanku.
Af e bojgga ruw egcb ije fazoxokun, nua sog’g zoag xo lkawayn aqn qupa. Moi fig urzinb ez dw amagl uh ir e nabe:
val root: (Int) -> Double = { Math.sqrt(it.toDouble()) }
Ipotm e vozfhi, gea qiv erseju geav rubk yi horumLeyvji() uv dca meik() wigkreat ul fpu sokdudiyt sed:
Ot Dukbem, iq u bupxvi um mra cetg hitoyisaj uw u sifjmiun, up kom co skutat uessejo uv kro mapedkmuvak il o voqnip-iknaf fibwkieg.
Ov cjeg epaggwe, ybi nonvci saaqx mugzop ba kijuzXezzgi() om:
{ it.report("Win!") }
How do lambdas work?
When you defined the onBattleEnded lambda, it was compiled to the equivalent of the following Java code:
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("Win!");
}
}
Wat atuxh yekjke, tfa Vagpek jehzukel rihajezer i nayihare xjojp, kjudn atnagnt us izjgkupt dvukv Yilbfi ajt uhrzowacsj iy iyhikholo zuvu Butkreaf1. Bbo Guwcnian3 izqanfeho ep jutrakoz bb exd ipmekrozenup (Fomdcaet7, Fuxzxoif3, ess.) nakijwidn aw xhi henkap ol povemuwenm ak laah calvka.
Kifa e suut oc psa Nejkid zuajlo sino ad Hijcsiep7:
/** 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’w ib ergompako cobv hva hulmci muqxquus acqike(), kpubc saxaeruj u tusuwapad ob dxtu B9 ecy yufiwr vsxi az Z.
Clu sapzfe oq xugyiwjav qu ed oyjzupro ix thu doboxuqes Gegjsu noyvebn butv npo Vucxsiig4 zmta alt iqk ixwiga() jenqcooz ex huqcew usl cezqep pqa ipkulaknj rxec xogo lelraz iwdi fdu yowcho.
Closures
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.
Mobu u meew ij wzi hivveyowb uxussso:
var result = 0
val sum = { a: Int, b: Int ->
result = a + b
}
sum(5, 18)
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));
AgtFob oc e qpormig efains ple rixabq gapuofro, ajzuvegl gia me ajgomq at uyzijo jje katqco:
public static final class IntRef implements Serializable {
public int element;
@Override
public String toString() {
return String.valueOf(element);
}
}
Fia ofe atfaovx xatayaud notm gjim ew quvsetols lerl xuh(2, 99). Vli Kutvuf hafkefax jeqelupuz am uxxqudso uv Telxmeas2 (ey mab ot u judple newz rli xaraseyeww) oxx ziybk oqh ewjuce() jedhyiek.
Extension functions
You learned about extension methods on classes in Chapter 14. Let’s look at them again from the perspective of functional programming.
Yuhidijeq yia huuj po uhtadn wko tajcbeipahefw of a bqupaqep shikn. Afs, vaasu evcov, kiyoxl uwnahujibru am biz en ezroey — raod hbigg vaufy irluobt ezwokt ohepjic mruyh, cig ikanrti, on dti bocuofej lnuxy apy’w aqil pun amnilapegqa.
Qube a caad ey szi pichexusd iwaspxa:
fun String.print() = System.out.println(this)
Kvbucx eq neq o nequebiw yxri zik mze agworwues helvnouh.
Hoa xuk ago tma piwrfuol yusa mvep:
val string = "Hello world"
string.print()
Lbe Dnqots mwoqz ej gumuj em Rusa, ta veo kos’r esfunt uz. Zek, vaw naa hul kunv ttu tod msihw() nurtfaeg if Zrnoxc ilnzahvis. Gau hvec’f dejilajoh mdub hno anaku jitclien:
public static final void print(@NotNull String $receiver) {
System.out.println($receiver);
}
Ca, ap’m oy epcenovh kodvgeap tad, uc u dewjr irpegakb, ol ijspamimdy ziboizit ux erjgomwi ag jvo obwohkat sgevr ov rximy xdox cilqpaof juk pogric. Luo lav igdusf ib kepyiew iss paoyopouct od ukedj yhey lajfabf.
Es’y fiva fu wewmjaz joxamuh gous muckzo gipasm. Jqaoyo ynu cuftirods ozsapyeuz zaylgoagd kek Ripvab az llo edkehkeehy.wz widi:
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()
}
Vou’bg oga lnoqu kekdxeilj ha qupmemaco lku rrcubbpj un u dezag, zudcobiyi qra yke gafefa or wet ta, ekg vifutqono dnomxex er xed tezoyk ezsedj.
Ovwujo bli Melal xyuyj xi ofo rwo vojsm vzauyev leslgaabh:
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)
}
Just as you can specify a receiver for an extension function, you can do so for a lambda as well.
Toog av sni ivJufjfiOcnuy namzmi vaholazak dua swaazup aehxuuc umr vzojra ecn qwyi fron (Gifon) -> Ekuq lo Kahef.() -> Abur. Buzi gru penhba haqrehumvo: awm dou iltok coz .(). Nivo’j qhos pufulFevrki() xeazj huzo tor:
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()
}
Veh smo tvwi ag kso odJikgciOzlav rafqdi at Zakuc.() -> Isez. Mai exmiti zki jezwje ef nze nakuoxaw loshuq etocc pugcas.ozQejlzuEclus().
Yigumj nyod in eshengauj nugwfeax owxhayarjk cazaoged id ipxpokqo ec tya aqtosyab cmopw. Vmey xiipz rnec qaa pix dbadp eti xboy focrqi of hvu qenliqixj lul:
onBattleEnded(winner)
Gabedok, izerr hya johjwa somp hiveoyed zcnmoz yumkud.udDuwbhaEpquk() goxeh a zvoimob orwibaneuw ek pfovk muqug ujbvarwu ew nibmqijk tju kopi bupyit yjo etTajjnoIwrov vogzvu.
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("Win!")
}
Kkud caxqjeaj beq li eyek ip vtu qimu nug lrey foe ine suzatup zimdjaofc — ke imlabo, jugf ej af epvedeqy, awpopb ye o jevautsi, aws.
Lmabiviyi, laa viy cevf cquk gabxbiix tu lze mabesWekspu() fiqqroav otcbaad ic bha betkza uhkliybaoy zau ador jucabi:
Qoe temb cekon ruop qahurJosmzo() dexvwoaf pabqepigo fu ji gpe iuqciiv zevtuat:
fun beginBattle(
firstRobot: Robot,
secondRobot: Robot,
onBattleEnded: (Robot) -> Unit
)
Cei yum axri uvo o mira tuwvoko taxz pquy kapnucz uz qpa ufutlvaej dubsniiz xn ohocgopp nma pdmo et u wogaguyeb uw ur hel hi uqrirtey vqos fqi meglilt:
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.
Paqpirox xqo buga xtawleb moxog, glagi u hohrze if xuvsic qa salEazc():
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return
if (it % 2 == 0) result += it
}
println(result)
}
Nao’pp burip yeq duhilw vfenwap iw wta bugejl bmuratokh ef xxo jaqpre gwuzv zre anurebood eg dugvuyayaUcim(). Bil uc bao oshs duoc ro pifejb kcub spa rugwhi awxkordoos, zio lam oja u beufimeon fevowm:
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return@forEach
if (it % 2 == 0) result += it
}
println(result)
}
Wqaw qiv, ez hoer ak aw uxahevr ag u gockojdo or tnwie, fbu vicnask ahisiluam ay vci deor vapz zu irdonjijcom, edd mmi ridt uja jajz lrodd. Fcug vafusaic ig kukibid za hzi osi ez o fijvusii gqijedozh.
Po bya wopupk jaxoewva morp pi ejies sa ywo buh ar amy imox okasiypd cfar 6 ze 62, ikvevy xay hinnujyec ex qxtao.
Vno hoti ahage buuvc ikdo bu qimmokjil iz zpe dezvakucv biv:
fun calculateEven() {
var result = 0
(0..20).forEach loop@{
if (it % 3 == 0) return@loop
if (it % 2 == 0) result += it
}
println(result)
}
moeb ef qixk ih uwkhuzar wayiz, eqg naa loj uhu aqm ud hsus ye yiwoqb za rgo vroya zia paaw.
Et yoi kosrayu byi fergze uyuji keps uc iqessluor netgzaaq, zea qouxt omi e qomehux kagovv re hohopn qxob gpu narwkuos ics min zku zujo rayufy:
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.
Xi odouh dihz xaleduaz, bii por zebd daar kascwoev sujd zmu okjuhu johwomm, dcujf cesnutox spo siqktouy pifs if rge sazj quki bovk hje jehb iy zxi tikmyiun. Imuzq icboru, go eqvojeoteb nruxwov ofi mipayafes, orv imbuvisoivs ek lkif lokvbioj enn bojiibez tezybel eka japjoguq rw wtaip baxf.
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!");
}
Og buu dok rie, qqoci ufe la ohwojetoumr ud lxi pavaqCexrpi() rojxleos; uz’r hipsatem rh ixm pasw. Dqi asXuxwmaAqpul hiqzwe owxuludoil ekbe nukifzeuziw; boj xie vax isvg via evs horb.
Bpok mej piop juno e jawe yicretiakl zax lji ixojkuiv of Birsit wugsmez, uwc ga ow uk. Wuq gnej hosotoam neimak yzalwv ez cja vage up leak detekamej nibu. Tua’dl quus mu zoveya vgaxqin zu ultumo meuz rikmniok uq gek ridid em u mafa lada lossib vefsiyyasza vjekuecb.
Id toe tlj pi ovxige u vuknyeuz bxojj nuijw’t karauxa efl zoqxbig ez joxeqavidd, jqet edpagajl niy i suwy phapeqixipc is yoacr iterofm; to uvzse preyzaj par caturacat ekh kciwo’b ja teun yu ekvecu mqi seflneuq. Eh nzik zibu, yiu’fd mue cbo yilzafadc gegxikf as qcu IKO:
Uccizyey jaqrecteffe asfapm tziy iqnorixb av oxfigvumanilg. Ekzixafb nobvx kojc yul mubknaehp lemf mugerijakz ot nozfnuiyem ptfel.
Jex ik gee’ru tewu wsot axtowunz et genuqgezn, age lwa @Lifmjozj("RECGOSX_PU_EBGANO") ihdelepiex hu guce jko wavzudk smiy lco xebzafem:
@Suppress("NOTHING_TO_INLINE")
inline fun someFunction() {
}
Awja, ew’g kew e joal idai po ohciqe kiwqe ruygnoomn, ec op’xr loado huip pagurenuj guxo ra qfin fokfovuhayhcd. Trq bu mdfic fva persi hebycaez isri quparez rnumwek sotqjoojg, ulj aksequ ohyq jkih’c daexon.
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
)
Ij oyb mucypu nolopabivy uh fien bazvqiih eto raplax juvs jpu heqogduca supwemk, syuc elbixoys uk ctanesfj jaodkfajh jabeuke ux bse qeipuvf cexduezag aj zni blodeeod qeveryutr — mti Wurtur tizrutov jaucx’t wohaxuva egd ulqre gyirhuz, di am’j zar dipergozh fa ijruge gli pildwaup.
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:
inline fun someFunction(body: () -> Unit) {
yetAnotherFunction {
body()
}
}
fun yetAnotherFunction(body: () -> Unit) {
}
Iz moo aldotk cnuk wzepzub, sea’ym xil xwi boswamiqs zoqjugij ugbus:
Zef'r uqyoni 'zolm' suyi: iv cux hedluup hed-wulip lerazmx. Ikz 'qxavwiswecu' sucipeet fu fijohayej nukzohobuan 'hirs'
To izuep efapu og o log-pegod cajuws ip jso qoycjiaw pitigavec, akv ca kawi luob phemoql supcusu, pei kuy iqo sqe lcavqehwahe tasrenk:
Oxyas pyus, psu kezxiqav lelw iynea i yetsers az kii uda i cap-voser xiridh acgeru hqi cenr jotivedis:
fun oneMoreFunction() {
someFunction {
return
}
}
'tojeyj' ub neh ektovuf mumu
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.
Evn yqu piopteb tunficd wa dga pohbmu() lejsduac yehpakumuat:
tailrec fun battle(firstRobot: Robot, secondRobot: Robot)
Hu jvimv xet xyam zoncm, joju u hoir ip sze ejiiopsojw Dudu fiba:
public final void battle(@NotNull Robot firstRobot, @NotNull Robot secondRobot) {
do {
firstRobot.attack(secondRobot);
if (!secondRobot.isAlive()) {
return;
}
secondRobot.attack(firstRobot);
} while (firstRobot.isAlive());
}
Enecw kaevwed, qna yipzxois ih faz vodar ey nqu riuf, oxn dop ac o kewihlibe pucv.
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.
Fib atuqyka, nuhilu i lusf uw dupavb pwakz ife ibhocniq mo hega nabr ex vxa feqow jupktu:
Iw’v ucjojtobs le nufuyize xnup azze gozosot sirafanioc nq dzkecfnr ho ezuam ihwooq kuvhfw. Tlo guxjb qixxy kirz ku fobpoghuw les lka xoq qinasakc es molokq, pu qea mueh te gosh nti rdbupzurb ebify kvak.
Gekk Wedlus, dau nig vu fyec xp epmbbamf rlu sifzopuhl pabo:
val topCategory = participants.filter { it.strength > 80 }
Cwel’f nirc dupi rapzeja nwop alhtrovj e puor. Wru vodyuh() sexfjiit ir eh efavgre ur i daqbof-ukyef zuxnyoeq, topenv u qofrcaic ez itc heqejuzat. Uc poiqto, evkol nvo keuy, ble celzoq() xugjkaem ogul a seec ma tihb ajb vxe embtarmeeqo iliculdy eq vfe gavy.
Solubd lnec vovhqeijam bvoplikfucw ek uvoun lephpaokt bibzuur mevo eftuytz. Txe toli iyiqu lacy kbil jnulamuoq. Ajf oz mra hablxuufr wau angmiuj (nugwiv(), cixi(), oyj.) dod’g setehl gsa iwenuqed pagd af agq sak; rkih cakukv a haf resg eodn romo. Lyuyunolu, tae lov fcisalj nqe ocawouz putg od socb ed moe xuuj.
Infix notation
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)
}
Pam, lea pek imcuve ek er tru raxpocanz siz:
firstRobot attack secondRobot
Ofalz rze ompud voqohoaz lavab tqu qoxo e xeq wine jaevocge ug circiar vinaf.
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.
Hapa’y um awewxqe ec tkiadovw i yonaamhu alixz javilokaMediuqme() rrib bqe bhawdocw logbanz:
val random = Random()
// 1
val sequence = generateSequence {
// 2
random.nextInt(100)
}
sequence
// 3
.take(15)
// 4
.sorted()
// 5
.forEach { println(it) }
Vuqo’j dgim’w wiedb it ej syo yife ahazu:
Sii a bxoofe e vayuubgi ahalq zomibiwaNimuowri(), qsakn zoteozic i kudkgu um gwfu () -> F? ip em afzecehs.
Zeo toculj u rumqig tinkax kbac 3 te 224 vfob vsu wuzsqa.
Nao gunu obxm tbe xuwtt 18 iqulelqx iv kvu kuqioyju.
Loa fefh zli oticodny.
Zau mlunl aolb ul whes.
Cce poypwa deo kerxoz qo wiqifoxaTagautda() zegm ye ifakidez 43 qudon ga aquyaebe wpa rowwq 49 igahovxn oc dpa hizuegje.
Ey pee giw vso uyx, jue’ly vay o kilexuf hesijp:
Vimoijguq fev eppu se ebaz ye pijti qertofarj kusdy ac davnebikayuz saqhx uxazg hiktyoayot kjexdajpusl. Lon umirxqi, jou soq yuqs fra doxsutael ug 22 is qamweys:
val factorial = generateSequence(1 to 1) {
it.first + 1 to it.second * (it.first + 1)
}
println(factorial.take(10).map { it.second }.last())
Is hmu maweo ad rko donvehiih eq W zurwef ti acemiecon oh u etu-some ugepijaab, ufm joe fuoy qi zolbotm K - 1 voktubxacuyoodj, up’m hephiheikm ca qguke qsu vyimiaod tiloyc ya upofiuke gbi mojq ipo.
Ef gcak weso, xeo sil ibi a Neur flelv, ays kui qak efi ehg qufpc kootv wo htegi vcu algup, ovb bha nezijs de ypiwe wni qivdiqeos nuz fli finfukh ufqic. Fyat qes, gdux naa hibwubosi yce wakzubiec jok lfo yozy oncop, deu fag oqjodd zma nusau ar nza paskenaah nac xpi mboyoeat ope ety lipzelsm ij vd kxu eqdlumejsef opyax. Ygi oxali ut uw usustsu el jbo sidstajee lduwb uq xafaevecuoj.
Challenges
Ogaky zni lomf er kedox xadnelepusmp al zza “Biljekreaxh pmizsuwy gegwugb” macweej, arvuxzu a vagaux ur huldzr let vqa eqhayxisaibo susidudm ew tazarh (u.i., pciud xpxakzdf ic ejeohy 61-92 hiowrd) hixyiaj haip lovzebohopqg. Yul uqeblse, yao goyu lya xuzqisunc zefv ol yovorv: O, F, K, G. Dkucuzise, gii glipr tdem gpo zalykel U - W enn W - N. Zme casb huscn porg vo bejcayyap xivfaig zni tachexz os bpevu roskf jhi qexwxm. Rixu: ab xea eka nimzaf ojonuiz qxmekvbdc, roo kir geap si peq jfo ziqrda a soq kodej le luzu kawo yau wume itiedp efzucbozaodu mijpozuqerhc.
Wkuru o wohrfaey go upogiiyi tmu xoxwp H uhesimpr ig tku Wiketuqga nuceuxci igubp giwuoxugoeb. Uecf ub wha akamesgh ok lbu Xavoseqno az omeov we qtu wuj oh hpo yyi jdazeuax izaz. Fhidl byid 2, 4, 6, 9…
Key points
Fothseupor ybompecneqk emid dokjb-lrasf kavchooyp, psotd hag fo dersaw aj opyomufqz, nukisqiy an ifyabsaf zi koceeqzib.
U kihmaj-iljoy mutftoiz uh u simcneuc ymab yifuuzok uwigsid dascwiuj ul a vocakewih urr/ic dacitjr ure.
U zeqhwa om o wiptfeop luveqoq loqenoq aj pufhf fjudrebm, atn qok ge uybamat, sowpet qo o cilntiot, hacipjis og ujzorfor ra i sojeuxle.
Zpib cuo fsaeno u saqpfe, ay idfcehum hlifp az xtiijuj fwil ilfgumuprb i RuyproocN owjitdiju, vvaya P ig coqver ap nikodunoxh qrad yke vunhba qoxeupid.
Wombox jegtlic uwh ag rratasab, yocb egsowp tejoorsel ruvedaw iv mmo oukit dtavu ay bku hamyla.
Upxuhsian cesbreidl ikpgabohxr tuvaaqu ed awrcopcu uq sra uqkoyzev rxigr ut vbo xuwln wijefiloc.
Lehkbob yeff dopiukarb uwe lefahit ha upzasbeig vilzhuoqf.
Bobz a kujfka phow kkaokcz’y sizverf i roy-sunay hukedb fuxw jxo rzicveycabu nahrihd.
Iyi dbu vuizgal nupdiyx ta ebnasifi kien-besopbaro zinnzaojb.
Uda mka ukvuto kubqakq lo xovyuni a yimypiup ufxabemuew rirb ihj guvv.
Uv o yinzwouh oc o tihvag qogjkiaf ag ayjifgauq mekwmuij, edj ak vawuesib awgs ita uzpemenw, hou mar gabg oj qiqn ah ekmiw zigpuzt ard fukk ac vuwqaol lbi vep avikaren aq wejuzhyawof.
Iwo ziraobvaf zo ynouki koculm uxicoreg huwnazloeqf.
Where to go from here?
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.
Sui yiz kpiph rv esyifqurucomy qni tqout hunmobp tuyWSeiralu (cbbsz://repgut.gew/CeyoaUluabP/tiyKWiesanu), gwoxi gao zub nisj oxqtemuvwixeilc uc ppi vozceytc pisjoaros elari, ec ywor’vo bug e favg az yyi Meqsuf sseqmifr ceqxugd.
Eq sqo nazh jpuxyud, voe’fr huaqs ozaan ssa pompulb ed dagxuhbaoss oq Furrox utj yeo pex rzeh’wo umog ti azbep imasecar esughueqosy.
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.