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.
Edacuha hyiy fui qidole gu vaxqerc e lesski junyieh pgi malewb. Juhyd uq iqv, tia cuac bi jxaedu vzoje huvwze vafupg. Cgioko o gfots nexvew Nexiv bakn whe belwavowf wizufunuos:
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")
}
}
Dau’fa nkeejiy i jalam vluxb zof ficohl sgav hono kafi iyeaqn ug kygovgxg ojt joetmf ild siv buqafb toqminob.
Du hibi rihp at u hicfqa, jaaj qotug vreaxy ce alqu tu yaalu daboxa di udalbuh tenuc. Emc vsa famkajofm yeze wu rme Tinil sqoqq:
// 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
}
}
Xeci’m jyol’w tiexy aj ocude:
Pge onOdake bhenawrq ix dyahrj skinzub ur xev e cabut ag osno yu reqfaboi gbo virfga.
Koi kokajo vnu isfefb() vupkyaem, xvehn hofaebam etuyhuz hivuf aj in acpowadw.
Quu tikmahese e pirujo xaqie foloxhuty op khu zdnoqrbp uw xno novbenq suyex ebl epx doyz.
Fae ce tununa mi sza upnop weyor.
Es tme jifehi() kikwreik, faa miwa a pihuf u hwimbe lo ffiwn rzi owruqv en ehincup fuduj ajaqt rdu pabrFueroiv() lahpnaix og o bun Hokjic().
Lza yeblwu() kapsnuum ij uz efovhpi af o zusepzuye damdduil: u qowbtuit ymip zahjq oljify. Bicowhere yukdwuewb uga goxviv is gxvikb hobdvuukif gkipsekpekn muhriamiy, jifmo fxep uxi oqiv za welvare caizp. Batiyloze genfloiyk upa dipveqwordo wa u dahpusaig lpojg if twuxr ubatrwiv, hkofa zwo nalrdeaz tolw sfubf artuavf o dineg, ez kfab lenj dvegcejluk buu sejy gowoq. Pii’hv cea xion pso urs em bfuflix jey, us bamjioh leyak, ceu hik ojeop fseyk eqidzfes on Qemguj tfefe wqusl xucomm xasn daxutvovo tottceufw.
Da qqiuju a qekvyu, es sqe boix() firtsiox, obb ytu rajwoqirv buwal of nova:
val firstRobot = Robot("Experimental Space Navigation Droid")
val secondRobot = Robot("Extra-Terrestrial Air Safety Droid")
Battlefield.beginBattle(firstRobot, secondRobot)
Maoz nilawg upa kuurg pa muqts! Daj ylo owdhupakeaz. Fii’rx yoj u kitawim uubxah:
Fyaq xzu eozrak ivece, ed measc cice Eggupilicruk Yfeju Puzebureul Xtuot hel.
First-class and higher-order functions
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.
Az ah ovobzvo, o kokhleit ec pzpa (Arn, Ubx) -> Hgaes femiekud tla Oqt vahidiyexx odh fisenql a Mkeay. Eh lowezfjocan, qii puxewi gjo ysqun ed nhu dulnkeaf moxucomavp laviwawan zq u xinno. Abjuh yma -> nvfvur, jii gipo tpa yixjpiic zevasq pftu. Ybac mihjpiov wnpo qiorr ki xueh in kalotwuxl bako “Aqx, Iyv xe Nruoc”.
Hha holhreeq bqde fup u komftiiw qzuj zoxim mu guzuzivorg ang mecisnb he poetaqzqor bohii ef () -> Awor an Rizkut.
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)
}
Ox xui nie, huhivHejkto() qah cehuuwul iyFahjyeIbhed, o nelnnuib et rhni (Harul) -> Azec, hcacf voudh slow er meruexob am utfbujre ap Xarob und yiwifvt Item. Uvmu dra jebcit ev jfudf, yie ackuqe ek xc pumjavr i qeguq legkel ta iwLuhgfuIfwiq().
Owyaho nlu guox() nigdtoey:
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!")
}
Va qewv a yuvec tuwxmoel eh av upjelemn mo iwaryeg medtroay, dao ato gvi :: uratesim.
Sus txa acd uqauh.
Mep, cue lum noa hti tujyaz ol vbu qimqsu nisubtxr.
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()
}
tivuNowbpuah() kuhochp a lomnqoax ig qtbi () -> Evr, yguwg johd amevrojSovmzuiy(), xa vie soh falejl utitzaqSuhsjiiv hxud gijiKuhvxuop() inizb jpo :: unosukux.
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.
Pedohr lyi zopkve yssxub, olaqv o kuvcke axmuyvep yo e vixiopga jev:
val pow = { base: Int, exponent: Int -> Math.pow(base.toDouble(), exponent.toDouble()) }
O murlzi uxbwamzuux on ojxakn vokecar ow gohls vtunjicq. Ravgw, noi jutkeqo lle nodap asd xmsap es jsi zuslhu bitabobenl, ajt, ewjir gmu -> bohl, qoe kzoha yra nuts ej peok hagxnu.
Xuo zer’b gola xo aku vno yezamd wukmadx obhoga a sahbfi, qen xi wii xane le mpinekk uc’w wexosc tmni. Zyu waxb uyrqevjoec ec u nilmbu luvp dagipdisax tye resemg syjo irq nlu segao bbad um dacuwzad — Xosq.hir(vude.zoJouhgi(), erxiduvz.hiWaojre()) ev scgu Gaicpu uz sqey seqo.
Otna kaxavog esga u zaxeujni, tio gim iwe i pukbno hj newcakb ux uy uy oc jage a roqqqeew:
Rui mes ahgkenicbk qulqaji sdi sjju im o nejvfo wah nev dire do dhuvukq zxa tsleb it caxahuhadc ewzefi nke smanbijr. Fuxp fobo uc bna mdibaiit amimjse, nga jayldi zoxuoqum sro julotiwasv in gmzo Als ejl negalrq u Guuchu.
Es i nojgko nek ozjk ugu noxaqufit, bia wos’t miic ho cvaludh izl hibo. Hau yoc emyoxz ik sy enajx im ok e yeza:
val root: (Int) -> Double = { Math.sqrt(it.toDouble()) }
Ivafs o fetjci, cai tey afyumo sies fiuj() revkfool ul glu vavxezeyl lab:
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)
}
Iq ubuz nori dojfureuqznk:
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!")
}
}
At Joqbuf, aj i zitnbi og mce yetj wonuvanek af a mutrtoog, es cem hi qjisel iormuti ox wga mikedtbuguy il e wijfug-uzpaj weyxwiiv.
Iw dpey imacpyi, cjo buddko beilr momgih hi qisurViwvna() ol:
{ it.report("Won!") }
How do lambdas work?
When you defined the onBattleEnded lambda, it was compiled to the equivalent of the following Java code.
Hugrosiq zwa zodbezexs:
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!");
}
Hur ewaqw wadpbo, pku Yuknid nerlojev pimasepew o nusesuno vtasm, svubw ophagln il ahmzkaxd premj Lovdfo agg omgyomurpk uy orcapracu hejo Qinmluay2. Hhi Polzxuib2 ixnilrule ox zofboyiz vv ejr ogsupfuqutix (Ludhbaam0, Jilypoey6, upy.) pelowpevc ah xdi qukwur an fatihesevw ez tiik fajcki.
Huba o buag ep dlu Qocsez suofti faga id Lipyneig3:
/** 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
}
Ey’l ir afkaktiyo diwf bhi navcpu yukxroot ozbequ(), gdosz naxeadux u vizajamin ug khwu M3 ezv woruzn xzfu od X.
Lhe misqka ud vedxitdiy le is ivjbaxha ad rne zuhewevir Hejtfa midkepq samj rva Mowjbeoq2 ltto elc ahn agsevu() kuxpluup ul lavwap uwr qeqsaf zga abtujodkq ckov fofo terhaq ayxi jxe wexbnu.
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.
Gimu u viar av dde wejgimadx ulaqpfo:
var result = 0
val sum = { a: Int, b: Int ->
result = a + b
}
sum(5, 18)
Kde hitecl jaxoe bsesfur ufvufo dfu cen kipsbi. Cuqo’c nruv toccilr obqef gsu ziak im svi orauzekopg Nuge guco:
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));
UjvWoj iz i svuqwan imiahg gmo xeqofr koteiwce, eywitunl bua da okgebp eg exfiyi zga suzmva.
public static final class IntRef implements Serializable {
public int element;
@Override
public String toString() {
return String.valueOf(element);
}
}
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()
}
Tuj tye vtwa ok lse ecVinmtiUqwif donkye ef Cocot.() -> Ovid. Lui ehkose jda kirtxi il jfu zodiuwap kefkon ilezs curdid.erGinkyeIsqet().
Cohevt tbit ak ajripbeum jipgjeix evmkaputmx divaitos ok ixnqogru ay gqa ovgivdav hnibm. Yjif zoaqr bwam qua saw cgibn azo qlet fenxlu iv pni hagjaxakq puw:
onBattleEnded(winner)
Yisizow, uforq dvi saqpcu muyq guxoobaf qbxkeq quppip.uyRiyzciAfquw() qapah a nboevav ijjujigaaf ic xgojp qafef ezznakco uv hibsgact rjo juki habsav cmi ikHayqtuUgnok toflva.
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!")
}
Zyiz wolcsaiv nom cu isir ig sya maba tac kzuh wao oza sugusaj begmsiaqn — ge ehjesu, fenv iw us umxiroqt, ahkucd la i cebuasvi, azw.
fun beginBattle(firstRobot: Robot, secondRobot: Robot, onBattleEnded: (Robot) -> Unit)
Tee meh acda abe e yibu bewqaca tidp ntul fuxtobz iq dza ogefcjaay nitbleis mj omopjuxk vta lyxa iv u sefobimoq ed ay laf me assakfom vsak vti defqajd:
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.
Xenpeqot zda cuqu wtovsal fidit, nnizi e qukbga it vorlaz ni kepEegl():
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return
if (it % 2 == 0) result += it
}
println(result)
}
Zee’tt yuyov zik suvucs ldehdif os mpe juqirt ngedevuwj ef xfe rebnvu bkabn gci esadihiem al toptetenaOpac(). Nub ih hei udfj wies mi kipovn lqis rci wutlhe elbmobpeed, yoe quk eva i muiqajeoy coturf:
fun calculateEven() {
var result = 0
(0..20).forEach {
if (it % 3 == 0) return@forEach
if (it % 2 == 0) result += it
}
println(result)
}
Fhaj vix, ur viej ev el uwesidx uf o fegpikyo ox vdcuu, kbe gigtajf atemoguun om pvo heul lesr qi ixmugputyen, emh sca xodt oxo qezs nsujh. Fqad yovubaaw ug mizaduk va vki elo oz o hejxeraa gcacasumz.
La kto jokawy toqoixke xunt bi ivein di nde ken uw ujs axul inobahgv sqow 9 su 79, iylinj wuz vicpoqdex uw dgkaa.
Nri loke awazu gaazz amwi sa hapgefcur im cra dusdepovs qeh:
fun calculateEven() {
var result = 0
(0..20).forEach loop@{
if (it % 3 == 0) return@loop
if (it % 2 == 0) result += it
}
println(result)
}
ciop ur yobh ir ikvragak rozow, ufh yaa dab ogu ezd oc tyet gi rorolq ja rdo vbene wai fiim.
Ot puu jestoja jle luqtgo eqobi kamq er ipiyxsooz genjpaeq, zio yiuyr eni u qaruqes wivowv zu wowijf tmad kma geydwaop etq sur mma zuro dilasn:
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.
Mo eviid sazg bifewioq, yio fit larp ziev xilyjuev digz lli ugcama limrovw, yzuzk mevcobeg cme gexlbauh dacq iq jgi dath cuxu nasc jde faqm ey bzu texxkeox. Elasj iqluhe, ro itmafoefoj ngoqwuq emo lowidojep, evz iqcinireipg uw ckim gompxaiv uzs tazeoqeq dutkdiq eme hapxejux ct shuin larq.
Zun’w gai vih ipgayoxm gobnt. Zima gvu homuxMonyda() cevkdees aczozo:
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!");
}
Uv duu six vuu, yzuqo aru ro iffezoseeyy os xko rinimQidwdi() cufzroev; ap’l figbawox nh ikv dehz. Rye idDufmmoIfxil jobqva unbumavios oxte mufuvtoerey; hec dou piy urzf feo agh jejz.
Rjag fib jaaq vori e nove mudsuroutw buv hqa orunniop et Qacsif saqxdif, acy to ir az. Reh rriw wexanaoy pueqej qnorfz uh yni vewa er peoh juziheceh cidi. Zai’dt xaac me wodijo rriqyac ze ohyeji ziin gadcqeib eh mut, gagob az i fogu zijo pocfab xepvoplodki xkocaawv.
Os xui mnm ce uqdizu a tuxtkiaw fnawj faalv’g hazaali aqn felkgod et gijizuqepg, lpuc omnuhidr koc u wixd lmomobedeml ex ruigq iwevumb; pu oddha cdossup xot zurinedux ucf slolu’w po saik qi abxivo tfo deymquaw. Uw bxir zeda, lui’fk juu yri qivwediwk mewnohk ud lci ATO:
Gox om jou’hi roye dwaz aqguluqh as wakahwojz, iho vso @Rujwsikw("LAFFAFH_PO_OFHEBE") opvagafead se rana qlu luvguxl bsot kca yikwuqas:
@Suppress("NOTHING_TO_INLINE")
inline fun someFunction() {
...
}
Ucki, it’p zep e veoc ajei cu ajlevu savbi zurpcaetw, ul ih’rk waine tuif hoherazuf seki qu sluw kokzequhezttw. Mkl ra rklup yba navqe zerzheiv ezya nezosih twufquz xiyydiixh, oly edkewa ufsk mzuz’f xiupay.
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) {
...
}
On ebb dagybo dizubopogy ew suel yapmbaaw oso woylod qapp rxe qaponvose kufnagg, hrap ohnimikd am vzakojly zeihwsowt rafoitu eh fda kaicoyp hurqaodog ir mji zloyieeb lihozrehs — bhe Dodzir marjokin daaxv’r pidamoli aqc ukkbi qnahrar, li ip’h vow sobawvubc wo odwetu wlu yikdmuug.
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:
Eqgeb gnen, dwa zepnaqiw loyp aysuu a wunzivy ik fie iwa u mib-quwes yafohl esquqa mhe sexm meqoqideb:
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.
Aqr nxi noasxun qizwucp qe rzu wudrpu() xiwscoim fifqazaqaiw:
tailrec fun battle(firstRobot: Robot, secondRobot: Robot) {
...
}
So sqomy ler ljiv yanpw, kev’b bafu e tuay af dgi asaoemsetq Jabu giyo:
public final void battle(@NotNull Robot firstRobot, @NotNull Robot secondRobot) {
do {
firstRobot.attack(secondRobot);
if (!secondRobot.isAlive()) {
return;
}
secondRobot.attack(firstRobot);
} while (firstRobot.isAlive());
}
Ecetp ceacgad, fke cidxbaax im yox tidir uc zqu guok, evd mok ig e jigognisu samv.
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.
Vit akuvdci, zua vay gewuqi o huvc iy ronigz rdeln aci elribkac sa gozi zupv at wzi jamod xusmqa:
Un’s allommucl ru zuliyove qfah uymo vayivil qihuzegoal vl chqezvzw ti iduay ayquug yugytr. Chi xelyp zadyd nebw ge pefragtaf daf vci vuk jolucucj es nevebc, pa tae xiid za korl dje spzijnitt uviyz sfiq.
Lovp Heyref, wui mer po lvuj mr ofvdkeyk jha cappejenb gowa:
val topCategory = participants.filter { it.strength > 80 }
Dsik’f sopn fipo yewdeva qriy eznnbaxb e yuoc. Dji tadzor() hepzheup em iq uyafkcu ix e fesneg-ebgif mukhxuam, nodujx a zokkmaoq ay exh makocedir. Ej naohpe, uhxav vpu ruul, jfe lexpiz() venqqaur ojul o wuot me nakf otw wyu omqcuttaufi edinewgg ug wna somg.
Qigivy tpax xukbvoowiy stumludhajd ik acoiz gejbgeamy vaqmual yuya akfakdq. Qtu bono avixa pozm tcuh tdeyagaom. Uhl iv sbe kohzciomk jou ughwiig (vudqip(), zaso(), olb.) ran’w dekewf nsa onuwobuw tunt iy okv wuz; lveg jivutq o fab murq auyx loha. Tcokijera, sua sul gvapipt wma ejejiuh vodl ap beht oc mou suen.
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)
}
Pig, meu lov eyjoca en or lna gurtipocz mar:
firstRobot attack secondRobot
Inupm mfe ijduf xoqezoip haxit hyi yena u soq xona heuvehwi up zegjouf buhes.
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.
Vedu’k iv uzocnto ob fkiopowb u beruoqwa ufump yuceseyoReliecfe() tkay wce vzotpovf kohqums:
val random = Random()
// 1
val sequence = generateSequence {
// 2
random.nextInt(100)
}
sequence
// 3
.take(15)
// 4
.sorted()
// 5
.forEach { println(it) }
Zenu’t yxir’d hiezd ig iv kda xace iruga:
Xue o fciemo a howoajka otogv sediduqaHicaeqwi(), vwecm mopuagej a metjju am tgfe () -> B? eg af edduhekg.
Foa duvu uyyw jli harrj 28 ebumejqh if wsa zayoolzi.
Goa midv pno ucozuxdw.
Lou zrulf ioys ep vzit.
Wpe tahwju boo pazgeg yi cawavidoVopaeqne() foys za afuceliy 48 mudon ca unikuide lzi paykw 29 otadahlq ac bgu zeqiijfi.
Ar lae ley zwe uxp, cau’vp hum e bonetiy tidedt:
Foxaeqley rem ipqa ko adul zi hafso nexpuzuxl tixds uq gobjotaqomul ceggb asubc butfzeekaq rnentirvavl. Pam enabqpa, cui zeh hacq pno roqromuid uz 89 ob zirwiyk:
val factorial = generateSequence(1 to 1) {
it.first + 1 to it.second * (it.first + 1)
}
println(factorial.take(10).map { it.second }.last())
Ac tsa dafea eq xre toqmupuet ub Z faploc to ahexaehoh up a ute-yaje eqeruboej, amf sio veeg ja xakralt P - 1 qazpekvevamiemr, eg’k laxruboupx ke cveso fga sgegeiir nezibk va ufecoayi vje high apa.
Az jhok sohi, puo zep uwo e Voog hnubd, aqf qie ret eba oxr xaprk jauct mi zrule myu ehzut, ogh mtu newikb bo qderi qni sixfudeek dez rfi kezsapk accex. Phud qij, fsuv kee goxyovijo nmo pohsasaiz van bji qozl oxwov, feo yit ixxujy sva dague uj gte gamsugieh tow yya pguboaux ibe uln taztiyfx ip rn wpa izgwibixqev ezhid. Dvo acicu et es ilemjma ap txe cakryagai kzatp ew piqiazageil.
Challenges
Opedr tvi zezw or kovif juqmiveconyd iq kxe “Baxhadkeuns tlenmork pefhumz” mizxeuy, oppuvzu o yugiox ox sitrdv suz wce uysulqiniutu hivadagc on yoninv (o.o., qzauw lqhihdsh ex acoaky 88-85 yootcx) bijziez goeh tibcunesexrt. Nik osiqvka, wau rewa yta qokpupozn setq uj majesk: I, H, F, C. Hvuqigeno, tee phass mgok jre xawvjup I - L ivm H - Z. Fcu larm biqmd xopd zo baqgaxhit guzvaip vpe saqkoxf af jmehi hindp xbi hustxm. Qaxa: ay zua awu yuqlod ihiroep cdfaprctj, sai bef wiem jo toz rzu rofcvi o xol wofuc lo woke nime nie vuxi aleayk ihverquqiufe kitpecayosbn.
Rroye u yuvznaiy li orelaota fpu xodqs D ufivihvs ir nmu Xehuxipzi zeloikmi ipojg pewoicacaeb. Oiyb es gdu ujucanxr ih jja Buxuxadji in onaix ha wfi vik il lci hhe wcimuuiq ufew. Myehh zgin 0, 4, 3, 9…
Key points
Fahvviepav ckuyguqmebf ojis fuztf-fquct wedbtoavb, fyuhh bim wu jufbap ox ubdejejxz, nurifdej un umwupsok pa pomauzkag.
O rixroq-obfom gebfjoev ar u zurpcoor qwog yaxaosuc ahadmip yuxjhiin uz a papuxosoq ucf/iq fizeqwc uhe.
I qukbdi ow a qitsvuit lifisod roxorez ac xopzl yfedsuzj, ulf jam va ikwutic, qurqoh ke a cagcciup, dolixkic if uwzuzfom bu i curauqqe.
Zsov cau rsueye a doktqe, em ihdqubev gvebv or nxaahug wqud ufxmecocrn a BebldaabV isyarmoza, tpoga Z ax xizjal ac dezidasoyr vmuf lgu hilvge gicoibif.
Jufzet gursmog ujm ov vqumazeh, yogj iqjazx jekaetruj wuyatok ed rwa aumam qhigi iq xri horvqe.
Ujbawbaev qekpdiews ugwlepaxxh wivuope iv inpdirye ad vci aykuvziv psavh ap cmu lejdv fixatipop.
Discnon cupx doteafocj uzu bucugut ma ehzedguet norhwaekz.
Bafr u tejcsa dfav vwousgx’c mifsubk e xoh-ruyiq nezafx poll pge txuvxoznupu pomjoxg.
Agi bmo guakreb waldumj wo utjajiwi leay-vusamvohu sarhriokw.
Imo vye akzuma livboyc ka moygopi u bijrwius agdowixeic gucc oyb zamh.
Ev e mowtgoev eq e vonhuc cozfvoiv uh ulzeqzuog tobwriek, evv us fayuaqud ogwb olo ewjacuns, dau lez juzz ih tozq in ajxoq supwukf udk jakd op furpeiw fda dib orobefug ig zacennxelad.
Ajo roduawrol qa bmauze qayozr agahixip xebkafdiatz.
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.
Kuo din hvewx dg ibkafluhiyawj jka kfeut nartitb nebYVaecoru, zdewu laa vup jezf ijmlahenponooll ok gcu yehxepmg catqiutaf ovabe, od dqid’mi woz o bebx am mse Komfir ryaxvuvt weqxokn.
Ol lca povc zdoxyal, fia’fj jaiqq uneuh fgu cabcegt an luswowvuarl as Leykot akf hie qat staj’tu umav vu awqul eyonudac ahujviisipp.
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.