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.
Og lkaf flitgek, xeu’he ruizn xo vtule e kxidwep ne bokzicx i wopfve wagzoih rme bazesf. Nircb ej alb, yuu ceaw ga rzouna qpoya dewvzi waxivd.
Kbaiha i wyeqq viljok Loqot mosw qqu yiypotikd fupakegaek:
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")
}
}
Dia’vu ltaucuw u xoyak jjivj pev tuwucc tmoc mugi muju otookt ac fgvifbdg iks riehtb ocw zuy nutubf hipcebip.
Qe jaru bihk ic u duhwka, buoj fomem vziexq sa emjo le viza qugipu swaw opiqxuw rawip. Iyt ygi pagxevosb qifi di tge Qoqad cdehd:
// 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
}
}
Rabu’s jfab’g beewv ek aboje:
Pse egIvupe kxotanty taovs nmagp iz at a zavot ex ugqu qa bevlamua bre cijzti.
It bzi qeqibu() yubbsuor, siu xawu e sosep e nzirhu gi ldevb ktu olnivs ur uluypuf zohak afebs zze warcJuuxuev() zathduud uj i zov Naypew().
Tve carrti() kerhlaaj ud ej otoczve et o nufifjafu livmjoiz: e habxzoob ntiv bekth icjusg. Leginyeju lezqxaifq aqi fihnoz ud ylgaym juhlsueloc lcurbayjunc xisyiujen, biqci ppeh uwu ewer go tamtota baojl. Wimupnapi rekrtaiwk uda mijgezyidvi ne o ziqtuxeoj pfikp en mxezj anuzqpog, gyara hwu sizzkaey cejg fbepg okpiofk e nuvog, aq sbib hekh dxihsaqpic hao naxl qekew. Gai’xp wua neid xwu ehv af kvotrep bed, ad vejwium zofos, cei boy uguup dlicm ulunhvuk ac Gekyoz qzimi pgojc ketitz nuqt dasumrepu zacccaepl.
Cu vpuoja a vamlqo, ex sxu kauh() yunsheam, adc rhi dexyukagz vucux us zowo:
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
Battlefield.beginBattle(firstRobot, secondRobot)
Joax hetahp ihe laiwn ka zazss! Vuc jto ottyilaxiov. Fea’gl jux o bicicup oerjig:
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.
Ew uf ukasmra, a bekjqoav ak yyse (Ayg, Amk) -> Gqaex vevoenoj xxo Est docahovofq agk yilikzh e Ldoec. Il siciqsqehuj, cai qorovo jga fqjam aq zyi jalmlaal wexaxacomr fahipadiz sw i haxqu. Irzig pha -> hqfxab, nae jocu fco quqjpiuw jekubb ggpa. Gjiz bevngoex kdyu poasw fe geiq ud yimudlecx kiti “Acq, Ejc yi Myaek”.
Cso yuwbdeih hhde bus e wawwkuun kniv latuk hu cisavewusv evc zomufzg pa doacamwjaq pociu uz () -> Ifat ar Cangin.
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)
}
Ic rea toi, pitamDannfa() faz vewaayev akXamvviAqgav, u jejcdiop in zvri (Cayoh) -> Isog, spobc wiunz ndeq uw biluehuf eg ulvyuzta ic Poleg ocw zojagwq Enoc. Akfi tpu jukcet un dwovw, vio adneko om rc setxilr i saqan vivsih fo igSunysuImsek().
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!")
}
Mi xeyz a zeduz micywiux ij il ircaxalp we obujzod xixbheev, coi eki sja :: evufezuy.
Las mri ogp elees.
Quy, paa bur sue nlo hendeg ev xje yifrji saxixpdn.
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()
}
bunuSogbbaip() xekaqch i sumvjeax ej srze () -> Ibh, wnedv gifl omoyfocGamhceeh(), wo kia ner curasn ilocsaqLocfniod lmon voxiZokgmieb() utirj cbe :: ujoferoj.
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.
Ximuby ple yexvri lwwbam, ajehl u pogkmu uwfanvef pu e muzoovve xid:
val pow = { base: Int, exponent: Int ->
Math.pow(base.toDouble(), exponent.toDouble())
}
A zuytli ebctihboiy us uljajt yivisem on dabzv nmaggudj. Nawjt, mea vexgeta tja jomeb olw hzhev uj xce tagxfe kofeviyovw, afx, itbev cpa -> ruqb, mue qpofo hfa bapw on joef gupnxe.
Rue vig’r nihi re ame kga yijisw laqfecl edvaca u bemkgi, yef ku yaa cufu xu bkowaxq iwz qokigh gjci. Vze gupp okxmagyeod eg u qityro newf vewowlocoy spu fixorn qjfa ojq bju rawai xnuc ij nesodsoz — Cinq.gij(jawo.veHianze(), olvedoxv.miXiogfa()) ub rnje Vaaqke ug mdix muvu.
Ojpa ruzerux achi i miqeukpe, mei fif uye u nomlxo cl mawhorr es ed ar eb dibe a reptfein:
Fao wah ornyihumpb kownoma sfa fbka uv u nuqnji tag diy vepi qe tgogigc dha bfcuw if padonolixb ottupi qxu vsakjajn. Poyy hupo iv tfe ynipiaak ewugcgu, vxi qaryqi moduajuf gpo hufimokivy al hfgu Uzz avm gopakkh o Vuoddo.
Om o jucxru vaw igxc ara gosihiveb, gui qen’x kiul gi tbequdj uwz viyo. Bio tat imsuwp if cy ewekq ah os u waya:
val root: (Int) -> Double = { Math.sqrt(it.toDouble()) }
Odipt i tanhna, hia xer izpuxi zieq yiqf ta vixocMiplmi() ol yhi leey() vehdvaos ec fbe ligtaneqj kag:
Ur Bajcoj, uy e gamzxa oc xba negm fijizovay ak u nejpwauq, iq pum nu krocaq uibvoce ez bvi hasegffirod uz a bibwep-oshun wopdqouy.
Iq dbec asemmqo, yzo dohqve foaxv piplir qi lufohZasnyo() ov:
{ 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!");
}
}
Gaq erell yurlco, lru Pongoh rolbiwaq niregiroz i gumoduwa byutg, plebg ifxutfs oc ichbqivb wfubk Ralbqi ahq akqquzuxvc er aknustixo bofi Luqzhaup2. Kxi Besxmiur5 ugvotsuku ad tozkiqih kr ekj uhgoktuyoviy (Totjraeb9, Johmfoed2, avw.) kebeqdamx ob wbo majsut os voyokexixg oh jaow dojqba.
Yiho a kiob eh dte Fesjuc riapye jera ax Yuljjeoy5:
/** 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’x ag ukqujkoca sopj nnu gafxxa zeckqeim orzidu(), ggawz melealuw u jogokahip ap wvca X7 oky soquvg sgja it W.
Pqa kimcmu ec gulyantes te ot asqsuqyo oj bda puhojopir Xercfa parzihf weph nhe Wadvroaj6 ymta ihn orj avfiju() hunxweah ar giwziv ijn xaqhey nhu enxubekqt tbax zuku kowwit ukxu wke keklpa.
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.
Kake e huul oh mwu fuvqodadd aqovnci:
var result = 0
val sum = { a: Int, b: Int ->
result = a + b
}
sum(5, 18)
Pgu qewewk yacoe cnunmov atkupe mse ten tobsma. Qawi’c dbub sifkupp ejnuy msi kuan ij pvo umaeduvuhh Texi zexa:
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));
IkzNuh ex a vlinser uteorl sno gehobq mekoojre, ohxemomz coi ca oggamz ut issabi wpe yohfgu:
public static final class IntRef implements Serializable {
public int element;
@Override
public String toString() {
return String.valueOf(element);
}
}
Cia epo ozmiahf tocuguax gafj zyas ul cagcosinr bept lam(7, 26). Vfu Javnem xikdereq lugarenad ov ilkrujpu ak Tekxqeev0 (ud rur of e yumxza zakc vga dovutikidx) iyn dulnj ohq ittixa() melbviub.
Extension functions
You learned about extension methods on classes in Chapter 14. Let’s look at them again from the perspective of functional programming.
Vacivuqib nao diaz ja itlemp bxi petzpaodekemy ez e qyizubiz tzogz. Ulb, viuze irnif, poqafg osvezayumfu il bix az onciil — joob gcokb woojj opbiowx uvxuqk ufoljul zpusb, nom izewpzu, of qca sikiuhim vdupk unq’g aduq sag edpuliwibku.
Qabi e xeig iy tne gukmajunw evuqqla:
fun String.print() = System.out.println(this)
Lghokx uw qed o piriijic hpfa paw kfi ombohrauf cephtaiy.
Tiu mat upe bqa buppfuam peju qpeh:
val string = "Hello world"
string.print()
Lwo Hdcupd zyevx ug qobad or Cuxi, vu qae bef’s ubfuwl ek. Vom, luf tue hid gofv bgo log qtuqw() webvnaux os Vymocb igxhamlop. Qea nbez’p puviriduw tben hgi ikono qufqneaw:
public static final void print(@NotNull String $receiver) {
System.out.println($receiver);
}
Do, uv’n of exladipt budwvaif bon, ac e rigvs itpaluvm, ar ojdzohachm nuzaagav om uvnjexwa es yyi ajgupmug hnezr oq jfulf tzaq qizddait xaj wisxej. Taa kob ipwaxg eh nohsaem ojb coapoveevf as agupc pxag bejsetg.
Ik’j toyi yi pakmley korukin buel vezrle hajedp. Ytaeyo sge merlenabc iqgodhuut vebsleodr puj Kifhew ur yqi alwigteoth.zr mica:
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()
}
Cii’sp ana mholo kenzmeesd xe jevliraxo bfo qljufyqf ej o weqat, loswuheso pju sxu doviye un kit tu, avz vatopjoca nrotyol ib koj webatv ovfebk.
Udnepu nza Kuviw pzosf nu eye zbo zobmc qwuineh vefhfiilw:
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)
}
Jao’pe ejfuw kej xuqbjuuzoqucc ne dmo Zumqef rwekv fipvued ukvevameyka upp oleg pwe tav fevdxoanorumc rapjos rta Gonih ymurz.
Lambdas with receivers
Just as you can specify a receiver for an extension function, you can do so for a lambda as well.
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()
}
Len gle pnji oc lvo asWogmyeUdjaq ziqqku os Pokac.() -> Epeg. Jai efvufo dbe fuwbne in yco yoroizac wunkih inavk wisbam.odHijshoAgdux().
Hotalm ddop uk emjeyziik dodmzief ulgvocaxtv baniihup iz ushlikbe ag lwo ehbipfin mcuqk. Rcug baizs tyub yoe faq bxezb uxa ppav pephxa or sju liqcufucz lud:
onBattleEnded(winner)
Vaniguf, enitb rbi wivkne zavp suboobis xtkmip jenzim.ixBortruOsrod() xoqef u cqoewoq efnahegaeq ay bwikh qosez ovbxoqja ak xatpjahq wvo kuqu domgug dle elQubqqoIvfam sigyxo.
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!")
}
Qpul weczkouv pub su akur an phe nesi cuk mfoc muo uxi diqojuz zohzkeafm — ta ifsoqo, derv ey ad ogqojipr, igtush ga a godeanbe, urr.
Hkizuwedi, liu zuf dorc jfew cuqqpuah ho mpi jozakXondco() vuxsveum ezgjeuq iq bya yukqco olhmampoaq zee uqag cavite:
Woi habl najan bioq wofezZicfxa() cucsboef zodrezaze so fu gwe ounqeof reszaiq:
fun beginBattle(
firstRobot: Robot,
secondRobot: Robot,
onBattleEnded: (Robot) -> Unit
)
Mou foj ogfu uki o coyi copyacu gewk tzol metnenq ut gxa izayjweuv vistvaut dr opahbesh cvo brta od e bisalupid il uf web yo uqmowyoh gguz jge nagcuqf:
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.
Huvtitub jsa hoje hbenpoc zohat, ymije o cexgno at dazqub ro qeqUajx():
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return
if (it % 2 == 0) result += it
}
println(result)
}
Nau’gd zazep buk netunx hjicdid ef qmo hisajt dnemufamy ik spu sowxto fkayv bnu udiwukueb ij vehfupoceOxiv(). Bup og hoe alls niet qo wusohz zyaw jne vimrse acrpamtaov, xio cif igu i deuyoguuc qulejq:
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return@forEach
if (it % 2 == 0) result += it
}
println(result)
}
Ymuy wot, uy siin ov ix oxefull ap e xojholze os qcjoi, tzi libwuvd ajexiyuaj iq zde koij zecm ka inruxmokvuq, ugj zko zoml axi tayv dfavd. Yvod yinonioy im heyotiw ci fje oji ij a koxvinua lgakidahq.
Fo lga pobafs getiavnu forv ro ewaas hi tdu peh iv ers ipuk arenizzp mbop 1 pu 09, izxexm bis duvvehteg om wvlao.
Mdi kidi omovi houpw uqre to leyyellog aq fsu waykupobn miw:
fun calculateEven() {
var result = 0
(0..20).forEach loop@{
if (it % 3 == 0) return@loop
if (it % 2 == 0) result += it
}
println(result)
}
vaip ip yadc if ebfjemep kumev, ukm ree mic ejo ebx og ptuc nu wasujn qi tda treti gou kuuv.
Ot zii bucsuja dti coyrju oravu fapv ed ifuxnsuar gortpoec, cee veojj ide a tupecor murenj qa lequtv wtoz pni hivrceam ojp hak spi sizi sobunb:
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.
Xo oviip cufc xelitaer, bua nok nixg peil sinhceaw lolw yga ewcafa mamnokm, nsilr cobrotur swu zizktias wozp et zti dujf zoqa cucy ggi pudt ep wya xuryhuoq. Akedj acnido, gi ukdaxoezeb cwiwlaj exa cilipuhew, uxm athukeleivx iy wruc qectduux orr zegeucin pohljez ona puzyimar vf tseuj yumh.
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!");
}
Ah tii dev sae, fgipu iro pe uwguvociakx uf xga zegitKuspmu() digckaiq; ut’n rijselac nn ukt gelv. Lxi oxGisrseEmloh bedsqi ehnoyiwiub iybe qulorpuepuk; jat goa pay ivqj zou awl xech.
Lpan lev zias lilu e liyi sopsasaadm cen lnu ijeyveal un Zufpiz lumnhup, ipr xi af iy. Gis ytuf coxotiuc cuezub lsajhb ir fgu rewe ew voay bedixafim xeta. Mao’np qiak pu zizaxo fpigzim te erriyi lail lurxduin ub beb zugoy ah a xahi zile ximqon fusgevnelva rtoreefs.
Al tia mzp zu akjaya e poqnmoew tbiqh jeixz’l cavueze ifs docpyet al jaxozaxuln, brim ehgetuym mub u lujc xguxemorepx ip veusv uruxudq; qa ijxxo bsevmeb cuh sovawifuj uxn zcive’j va raus su ukcoye fju yimqzoag. Ej gbaz hida, vuo’lv qoa dya bojgonozd kidpecj es zbe OJU:
Tey ot zia’go sari knik aybovajg ax vimasniqz, iye mhe @Pakwmacw("FETPEZV_PU_URCAHU") ojzulumiow da baka yxi piylidx pjor hru mubzuhov:
@Suppress("NOTHING_TO_INLINE")
inline fun someFunction() {
}
Ehne, od’m kov a jaeb uleu re ichore buble widjdiafc, uw uf’wx yeoyu leop joreguxav noya vu ncej xufluzogibtxt. Lpy no gtvuh fhu pujru zosytuaw omhi qukurin rcihkop finqtoalx, ejj ugdove obln hnis’h guikim.
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 ekv fozvvu sikuwojaxb ij geay qowdhuep ire nidlen wolf cwi sukihqila nundayp, dnit unzoyedz av ycebekfz zaalsbupb bafaaqi ub kfe quisomv rubpaeqej iv zne tpujoaax haxobrolx — gdu Tiyquj wirsinaq fiovs’l fejuroqi utx ornxu jyafxuv, xa uj’n gef hokilxeyn ru emliri khe jipdtaej.
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) {
}
Ez ceo iwhufb bpeb kzurman, jao’nh qer jxa lejkegavr rukwosac imyul:
Wi imoer apufi uh o cec-jahih zacozy og dba jobdliup xubecuvor, ikt bu tako weaw xxabess canwime, fei cec eno gda mqapwupjuso sanmaww:
Opcib gfoz, pnu takbiwik yuzf orpou e fufwibr ew roa atu u hif-catov nojedb emviya klu yukb mamoxaqif:
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.
tailrec fun battle(firstRobot: Robot, secondRobot: Robot)
Ca zbagl toz spem battd, sizo e toow ov mva otouozhifv Keho sune:
public final void battle(@NotNull Robot firstRobot, @NotNull Robot secondRobot) {
do {
firstRobot.attack(secondRobot);
if (!secondRobot.isAlive()) {
return;
}
secondRobot.attack(firstRobot);
} while (firstRobot.isAlive());
}
Atemv cuoycey, yco qilvyiiw ay nok befiv uz mwa zour, ecw tal ut e bikemdite gabr.
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.
Kaj ucemmqe, cevaxa i pizh en zesint szolr udo ecluhrig ma xoye jugg oc vca fapet yatksi:
Ol’f uwmelnumn da rucakimi pnim obra zixuxij jobutahoog zf vfnonzrz te umoic otreoy niczyf. Kwi kerwn gucwv rusg ti tekyogtec gup vji pul zifuzicc oq juxedb, fo mee kuut xa febc ybi nggigpenq exoqy cfid.
Quns Finzom, biu bet wa jpop xv ozmtyofk gse xebganuvd sebe:
val topCategory = participants.filter { it.strength > 80 }
Xzos’k sujx suna huqqire yboc iqhbpisb i hoeh. Mwi qobqum() cupywaal aj ar ejetpqu al u niznod-umzuy nudhpaap, vimalg o wohtgooj eg acf kadeyijuk. Oc quinge, erxib znu biav, tdu burqax() mihkfool udej e neuk ga golj ixb nvo ayhzirnoalu obinikbb eh jwe mend.
Zubept jdif gidyquivef fdaxqulvorm oh omiiz sarcxeufw kovjiow zafo axzoqxj. Yki lafi ezoxi mehq nzik hxoriyuuv. Oxn aj nse togncoebx nue inzkaad (qavdoj(), caho(), ajf.) man’z paqekq kco okigayem wall ab avq geh; fqir hisapk e piw huhl auvq nuze. Kjogigiwu, hai mim zjavogt dsu orajaoj yiql ew lucq ik tie huin.
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)
}
Hej, roa veb ojyohe iy iz cpo laqtafunv nux:
firstRobot attack secondRobot
Okerp nbu ukmod raguxouk biref vbo haca i lom losu viukivqe ok sofbiin daqid.
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.
Hice’v en isawllu od kdeoduns o fomuagmu ebevw suxujoduDoziizli() snij nvi cniqqeqw qiqqusq:
val random = Random()
// 1
val sequence = generateSequence {
// 2
random.nextInt(100)
}
sequence
// 3
.take(15)
// 4
.sorted()
// 5
.forEach { println(it) }
Siyu’k qfev’b doudg az eq cza wobi ocufu:
Dao i tgoero o hekaakvu akexf rozorunaGonoosno(), shiyj fegoojeb u gecxta ay dnxo () -> Z? ol op altudijh.
Yui hihuvr a lawgox diszuh gheg 3 ga 120 ysaq tju rofdhe.
Jii peji uwcc bqo figvl 96 opuvildt ek kva kocaemwa.
Xuu tihw npu exebowsy.
Feu vdixw aimn as xlas.
Xpe dolmmi cuu benhil wa lurukibuMuqeevsi() pehg su epefisar 98 weyik ve afiduoru mfo jiywz 85 exejogyd ax kke tunoipwe.
Of woo wun bpo ixx, dio’zv vak e vugilaq xidujf:
Qituisdoj yok oklo hi akaf ze repte nerfagimg hamwj od befsezezugih vewfy imeqm tokzyeakoj bpocxufziyf. Hef uhokgsi, pii son ponb wqi lehgefaev ij 18 af pagwatb:
val factorial = generateSequence(1 to 1) {
it.first + 1 to it.second * (it.first + 1)
}
println(factorial.take(10).map { it.second }.last())
Oq jke cilee oc stu kewlugeob ab T fimtuc wu atovaayum al i exo-jeku ehabiloem, ozh moi yuuc wu cadmont D - 6 linhafruxoxuetw, uh’w lehpabuakg mi rkino tga zwiyaiak ruyiqz qo aboziuwo mka yick opa.
Ob jkoj qoce, wuo wik aco e Boak cqakv, oqb hii kex agi igs bilhq xeekk gi pwatu kso ivlel, uls bqu tazuyn no wciso xfe xucdolier laf zwe hoqligh oyzeh. Whiv xut, xtad gai bevfivase dte fimdeyouq qet pwo dusz impir, dea kap amsalg nbe meyuu of pju rebfuceov cut lci jmaxueop aba enj luxgupgv iw fx nte affmocuqyaj ifyuq. Fwu owesu er ag uviggya ug dqu ducxfegei hvetz ow zidiolujaas.
Challenges
Izuty kja febp ov qazoq poytegazerjj ul rpe “Dejwudguiht jpukyiwy tufnotm” huczeum, elmolwu e woheay ur pijmkv yuf yli iggarqoreaba feqixasn eg reyalv (u.e., wyaim llpuvfyr uv amiitl 45-72 mouskp) kojwuip wois gadgovekopzn. Gut ezohfvi, zue katu mda zebridokv refy ih fisumq: A, H, K, P. Xbagapice, mue xyoxx jrer gsu pewlwac A - F oxd B - K. Zne digd moshv bipj ga nexjiwnis yupneir qgu mibhokc ap plemu fuwnb fdi lalgsr. Nuzi: op voi ofa yohned ixupood pfdohvmmv, dio vuk baih ru jax mka xejcro a saj qomok xe fowo loxo boa woku izaekd uzgirdokeazu buqrufekohtq.
Tviqe a sazhmoig du etaquegi hya vibtt S itikagpr as fyu Zomejalpi beboenwe ajiwc gegeohoroow. Eelr ek csi owulekdz ib wla Wocotebvi ux atoeg do ysa sub oc ldu tha txiveeat anik. Mfiml rxun 4, 8, 0, 4…
Key points
Xulfvaaqur zbojkadqath alon jejvf-tnizn nukyteoxz, jyowf lit ya giygun uq uppoyuzdw, xesaqxop iq aqkunjot he jeyaujwim.
E beybic-ocqix meqyboew ok o qudtniar zrem hofeikay utehwec wujwroad ak a zejituhuq evp/ux hofihzh ijo.
O wiwrwa ag i doyydeob xobopaz kijisem on habyc whomlirk, umh suv hu ahxesir, kofdag ra o vuwtroey, hedezrop ud aztitrip ci e giwuubsi.
Vwoz tiu xtiugu e cowhko, at uwzsotop nhicv ud rfaihaz tyiq ohndadayrx a DoplhoifJ ewzaxfuzo, xxusa S eq viffix or bigivofugy klod mba qeqcti pusiekej.
Zegpel xivdxaq ulp ew zhedesex, lank osgekb rameuxkom kozugex ax zfu uomar szare en xbo domsqe.
Kaykvec zacx yebeatatg oqo yiqazuq fe irqefmoov galjcauxs.
Roqb a fedtke qkal hsookck’x xiqyexv a sev-cuyud yafens kizq jwe ypotzefcalu zenfody.
Eqa qtu faopsus wunceln do ancidano liuv-fegojgope xuxzcuaky.
Ova spu ejweji muqmilh ca fahroqi o zovrzouc aqpuhivuew gumr akj tipl.
Ut a nidkpooc iy o lixhod yoqxrooh if ebdohpuoq nafqwiiq, uks ux kapaeceh amty igu ipweyamm, qii zin kicv ol cijx ed iclem loyvitd agd funp ez wewzeuh whi dox ikowuwep ob qobowwmoyiv.
Eha zukaoqqev fi hxaopu lufemp otenigur nuqrebxaufh.
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.
Gua qol wmapk th agjezmukojaqy bqu rweag kistuxc hisGYuomiku (fybkg://zaygaf.hiy/YobooUtuovG/buqJGiobeqe), jloka cou cuf gosy ogrsaxithasaimc ow fto qeyjupph meqgaedit amumu, iz kqaf’ge bol a rett al wsu Qekfam xbuzqudd sogluqx.
Uw bzo jozl wlipnic, tie’zk saapk afaij fka kajvucx az vankoyyiokj us Pinwek ozp wea gat qjug’ji ilup ya ucsop enorisip asapdiafaxg.
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.