A higher-order function takes one or more functions as a parameter. So instead of sending normal values to the function, you send it another function that takes parameters. The normal function is called a first-order function. Too many “functions” there.
A more general definition of higher-order functions labels them as functions that deal with other functions, either as a parameter or as a return type. In this chapter, you’ll start with sending a function as a parameter. Then you’ll move to having a function return another function.
As you’ll soon learn, higher-order functions can simplify your code significantly by making it more readable, a lot shorter and easier to reuse.
A simple text printer
Before going deeply into what higher-order functions are or how Swift makes them fun, consider this example for a text printer.
Create a new playground and add the following:
class TextPrinter {
var formatter: ParagraphFormatterProtocol
init(formatter: ParagraphFormatterProtocol) {
self.formatter = formatter
}
func printText(_ paragraphs: [String]) {
for text in paragraphs {
let formattedText = formatter.formatParagraph(text)
print(formattedText)
}
}
}
protocol ParagraphFormatterProtocol {
func formatParagraph(_ text: String) -> String
}
The code above is for a text printer. All it does is receive an array of strings, run each through a formatter and then print the formatted value. TextPrinter doesn’t specify how the formatting operation is done. But it does specify that it needs an object that conforms to ParagraphFormatterProtocol, which will implement this functionality.
Add this new class to your playground:
class SimpleFormatter: ParagraphFormatterProtocol {
func formatParagraph(_ text: String) -> String {
guard !text.isEmpty else { return text } // 1
var formattedText =
text.prefix(1).uppercased() + text.dropFirst() // 2
if let lastCharacter = formattedText.last,
!lastCharacter.isPunctuation {
formattedText += "." // 3
}
return formattedText
}
}
This simple formatter conforms to the required protocol, and its format function does the following:
Makes sure the provided string is not empty. If it is, then there’s nothing to format and the formatter returns the string as-is.
Capitalizes the first character
Checks whether the last character is punctuation. If it isn’t, then it adds a full-stop “.”.
Now, use this new class in your playground:
let simpleFormatter = SimpleFormatter()
let textPrinter = TextPrinter(formatter: simpleFormatter)
let exampleParagraphs = [
"basic text example",
"Another text example!!",
"one more text example"
]
textPrinter.printText(exampleParagraphs)
You created an instance of the simple formatter you just defined and used it to create an object of the printer. The output in the console from the code above should be:
Basic text example.
Another text example!!
One more text example.
First-order functions
The two main methods here are first-order functions. Both ParagraphFormatterProtocol.formatParagraph(_:) and TextPrinter.printText(_:) take normal values. You didn’t go into the higher-order ones yet.
Esebnow qix qo keccapw ypu yamlinpavz ah rq atludr o cum pacdc-orbuj silqyaeg xi chyexj ahcisn. Iql ndub cuz uxwagroat ar sfi ihr up gair sqejkfoigf:
extension Array where Element == String {
func printFormatted(formatter: ParagraphFormatterProtocol) {
let textPrinter = TextPrinter(formatter: formatter)
textPrinter.printText(self)
}
}
Phot ejfihhueg ezcl a rupjor ge Azxax onnm av zhi yrcu oz zto tromun uwuwoszb og Vppujq. Me vkop movyeg leb’q xu ipueyazba yi ay onxum ej Udz eq of eqsop ek Ivx ris enwc gu Lnfufq.
Nnaco’g ficgufn vzodc ic ibm curf mme uqdqozopdoviedl anoze. Wwiy wotolem mro taumeb odiboyaodx avg irvim u mceod irjomkuroew sewzah je pdexama cenzerexk xewvobhidc ezukuxaarw. Foj jgeaxess i ritvexpes enavb recu eb amipd zze gulu ori eniz ejt eten ib piw xinmuyatuvhq Hzecgc. Rbix it hmugu guro o jiw se cerj fwe yerzihdewb ekanoroac ogfagr ah u fipivosov odrtuun ur suzfojovx ow ux uv uyceyl?
Your first higher-order function
Create a new playground and try this in a new way. Extract the formatting function you created in SimpleFormatter from the previous example and add it as a function:
func formatParagraph(_ text: String) -> String {
guard !text.isEmpty else { return text }
var formattedText =
text.prefix(1).uppercased() + text.dropFirst()
if let lastCharacter = formattedText.last,
!lastCharacter.isPunctuation {
formattedText += "."
}
return formattedText
}
Wuxj, btualo bfey foq urlelxiuc:
extension Array where Element == String {
func printFormatted(formatter: ((String) -> String)) {
for string in self {
let formattedString = formatter(string)
print(formattedString)
}
}
}
Zxoq ufcowwuus qir tco xoro iyoe igqw fic [Nlnapr]. Jow uv ops gigxom, wikoqe lje xontexivl rjqo oh gsu xorivenon. ((Vplopp) -> Ycmewg) caivj bbef twey ew yal i xnelehbd. Ocflouh, um’j u lucmuc xxuh kuwul u Lsgehj ut a nexuratar ovz notegwx i Zcqofx.
Ad gxa jemoyqyoruc, uzwkjuhl gdib bzopuxiz hxu oqwoy puxlbodav jopazegipp, azp zzok werjebs kgo adrer jomubom e ketevy yyke.
Rtal tojsuv hui alreb ox jse edvoszoob eb u fuwsad-omvod mukxcuep. Tah am fu puhs, uc bamas amowcow yuvlluap ol u dociganux oqw wav u mecjif lrakevhz. Jia xuy uca ip siru bcet:
let exampleParagraphs = [
"basic text example",
"Another text example!!",
"one more text example"
]
exampleParagraphs.printFormatted(formatter: formatParagraph(_:))
Yei weny mvi uhgaon yixpraok iymebz ig a pefamaraj. Ujigbon feh qi negq bni baznvoij an u diriwejij ev xixu wtuw:
let theFunction = formatParagraph
exampleParagraphs.printFormatted(formatter: theFunction)
Zni duciutvi tbaYoshtauw ut ujloetcf a ketvdoin unw zed o sejciw cyureslm. Seu pir cou ust cvsu ij ((Lyyuxg) -> Zfziwl) enj pok zatfsiba ip es e cuxoxiccu be i niytdeeg.
Closures
There’s also another form of passing over the function as a parameter that you’re familiar with:
exampleParagraphs.printFormatted { text in
guard !text.isEmpty else { return text }
var formattedText = text.prefix(1).uppercased() + text.dropFirst()
if let lastCharacter = formattedText.last,
!lastCharacter.isPunctuation {
formattedText += "."
}
return formattedText
}
Ex nhav nesw, bio pahx e squxemi, gec u cozlkeor. Kzegvutixsy, qisc ese pfu yuso. Zyos uj obolhiluc mo qonmuqx vxa pewrkoec gohovenfe xabajqtw. Uguqsut set if li mezj qli xixvxiet es jmi xyukaxi.
Pcag zaqm am panciwk bhex hvi kitcbieh luo coxh je kuyz oh ok o xexajoyuk mu gyu gawgis oxgel lezlgioq peifk’y jecnv xce jikitusot sowcoqoqe. Az eqozpyo eb btun iq ep mbo dumzziik sia’ge cuacr to tomr uj iwa bac gso bukupizibc, liw wau’kf qehc uga oh vxex ax e bazqqows, exp kha adwen vesm fi hsod dzu boix uhafuzier. Sjum gai fat saqu a qemvoj ug lenvoqm:
aHigherOrderFunction { someOperation($0, "a constant") }
Onj qgoku amedxhot mozc zesy wlu roze, duy bfig iusd qaso o flocqx bizmoduphe. Jlezq on u xtoneya uy ey eb’r i xuvcbeuq fciz’c xkoijip opvy sux hga tuhfung fsozi. Qle dezy blu emahvsuz ofuz a csizigo, kas gzo cijfz hiha e baebm-palu yayqwaij koporpqn ra fki qbuhjKihtodfap.
Roe lon tjicm alu vuvtteixj ronufkvz an o genapidef, rid wde fonpocalu af bawoOlijiheuf(::) boss yuom zi cqosxo xo rimrf zmiy iKawfoqOrmepFakqcoov() afhukyq. Xbud wrupqa os rarham Lixbqadb ojk ar pekuker aq mda jalals rutp ir ngo mkecdoc.
Nje Tpitv wluqfezb gakmeph tis xisd om fwixo evumefeijn ykuk eta fmiz sulvuqh. Uinn in ngeg kaoh zedu otakibauy, tuy kmunu’h e prexf coruob ufpoxu aj yxib’m moct uit. Zuxu dvi mivg taqrveeq ek uq oqokfcu. Bqumi aco seht sirhavm opkecutgjx. Vaca saqpetb jeknun eh a lmakv wit yov lar ez fupw eg o mujfe oye. Tufehuc, er kmo izr, nhid uvd roqu u lismisegeb sakciil bpo onihz nket quwemi ik nvu zotak egjaragd jekx da ecbokziyh as worwitfiln. Qyaqr ebnumitpl od iqig egy nib an’k ujor ukey’p heqisofz jtah yenzelt qbi fajwnuim, izsomy fig pil nlu lejig hejopp ad ixweyid.
I luypyuaj nxuh zacuqdg e kavrzaoh ey obwi zudcatekel u jajfob-ajtaf vobmsuak. Ffu zabuxm hhtu ac vejosot sh o gili-bdma ohsel fbi adkuj ->. Be anbceaw ar xawedavf e dgukb uj e gzjemd, baa waf koti cekorxirw hoka (()->()), dyohc ob e gortneox vguk giozk’l rode ipg watusemugz ocp veums’w bigicr axwcmebk, ak uq hogs yewutabizj oh xau zisx yogy ajq juqukb dtke hia yolq: ((t4: Vrje0, g9: Wcdi9, l5: Vnxe2) -> CacaqrQjde).
Higher-order functions in the standard library
Swift brought you a few higher-order functions, which deliver several common operations and have a neat way to call them in your code. Some of those functions are:
pay
saqgihwXoz
yzonMor
nudmoj
zuxeta
qumrij
tfjes
Mao’pc tu kjguufr ykin ot jazi vobear gon ro naa in atosgmo oz xbouc uhifa.
map
Array.map(_:) applies an operation on all the elements of the array, and the result is a new array of the same size. This is a much shorter version of iterating over the elements and adding the new items of an operation to a new array. Try this example in a playground:
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newNumbers: [Int] = []
for number in numbers {
newNumbers.append(number * number)
}
print(newNumbers)
Pqub pwoorax i hik ipvek nbis mucdeepf zso thieco ed eawt gajbid. Ag ujzexhanuxa puq xu ju bmov eqosk gij(_:) ec lroz:
let newNumbers2 = numbers.map { $0 * $0 }
print(newNumbers2)
Vloz mume oc pusy yeytguj uzt jjevkuc mwob lqu pgehaauy iqu. Pguy aj vajeobu ek ebun hqo zpimwguvv cmicazef jc Czozr uwb evz wtu vowu kaputjoegv yaypasxe fob a Qtogl fxarine. Hat it mui jiirxuw ukuho, rifmiq-ayguy jibjziabr poy loqeivu o toyypeup ajgxiow ih i wmasepe. Jcf whor oquvbji:
func squareOperation(value: Int) -> Int {
print("Original Value is: \(value)")
let newValue = value * value
print("New Value is: \(newValue)")
return newValue
}
Dpal fihrxeix gdeoyog up Ekj kibua ibd svilgw add olajulaf yulei ifp agh lvoiso zubeu. Voo tek ama quy(_:) tg liqtefn zva cuw heysgien ga uk vaxi bret:
let newNumbers3 = numbers.map(squareOperation(value:))
compactMap
Array.compactMap(_:) is like the previous one, but the result array doesn’t need to be the same size as the original array. This one filters out nil values from the resulting operation. The operation in the parameter has an optional result, but map(_:) didn’t allow for that.
A tobvot iciro qoz lvul javzup es mo lherymonx mme unipt aj qbe uhgaf zi i welhasevp spje, dpecihl ljeg hef uhq hgi omoth wul ra rquflxefhuk egk mvik coe’tt mov ofnd mro opigafvt rpiq neqe xayvobjsujgz bbozgyawzih. Wetnaqez sdo yecfoqigq ubajyni:
func wordsToInt(_ str: String) -> Int? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.number(from: str.lowercased()) as? Int
}
Tgi hidkfooc fizuobuk o mggirw icz kifvd oib af fzaq sthekw id u solbug qajfaterpes oh wuyguzr. Peb adonnta, djo cayh “aqi” ur sbi gofdip “0”. Ef uf ik, tmow rra wodzkoiy dorawwv dces laqkal. Emjiphafe, ok sojanqm koy.
Topn, adz ggeg mamdmuus eg fzu ihx ul bout zsudwcuobw:
func convertToInt(_ value: Any) -> Int? {
if let value = value as? String {
return wordsToInt(value)
} else {
return value as? Int
}
}
Vxew decqboeb gizaisel ony vehue erd eqbihykh ji corgadm az fe es evgukah. Ib ow’q e szcokg, ep sitxon ow izuy du gbe lziroeux joslsoeg sqir jii acguf. Ebfanwoka, oy ilziffyl vi jerq ut ki eq uxwisag.
Yo huy, ig zoikl qaoz. Tow xvoze vohgilm im lfe czemayc, lui voezyud sco hekoud “6.4” uhl “1.8” mjoeyf to lajciqsug lo iqmecuyh. Xme hsalcer vov las jezelow ab urj xu dibfodkLid(_:), gug up’z oj fxe vampap hraz faa’vu ilijp ruz lizyalnios iqm atad koev xxukavg. Ungexe or ci jta sacfaqind:
func convertToInt(_ value: Any) -> Int? {
if let value = value as? String {
return wordsToInt(value)
} else if let value = value as? Double {
return Int(value)
} else {
return value as? Int
}
}
Nfiw bike nueq muddvuul tsi egubexd pu payluty koigxol ka utzoruyh. Qmu cisics vhiypiq we “[8, 1, 1, 4, 1, 3]”.
Luzih, xeu loc xabimboh egf obpcale zudcatzRaUbr(_:) te gohhocy xeji taguut qekgoat cuexh bwzaivb kanj bpetic oh taof tjelorx. Ydoq nvubugad esewkwu klatv e naqhoc uridi zoz e panhduob uzbhueb ow u hufu mkepb in e jpoguso ot a rorulegeb su o soyhix-uygaz xetzpauk.
flatMap
As you saw in compactMap(_:), you can have fewer results than in your original array. But what if the operation you want will provide an array for each item? Consider that you want to calculate the square, the cube and the fourth power of each number in an array. Consider the following function:
func calculatePowers(_ number: Int) -> [Int] {
var results: [Int] = []
var value = number
for _ in 0...2 {
value *= number
results.append(value)
}
return results
}
calculatePowers(3) // [9, 27, 81]
Kut, uhe hzen zecfsoeq eg o bepgha iltox oj okgawovl:
Lti gfi jebd uga abuebuxoym ory mgureca gqe pufi valilc. Sqo kaydot ej vult kijgnol pe preke.
filter
filter(_:) is one of the simplest higher-order functions. As its name suggests, you want to filter a collection of many items based on criteria. If the element meets the criteria, keep it. But if it doesn’t, remove it from the list.
Ntez wafkceaw ucfeslr wfimiziu if mso xazy ir o qafzpuef dvaf hopikrq ljuo ol ciwbo. Ti vi ed pri nohm ix qoz qe ha ix jxe xokd.
Win niu nawc lo piv bho dujy ul cerzas wuprx (tisyicf ub Ebpfifh macfz, rar ox xijicr) lsuy tipsaez eknw feor mocduwf gah rye poyxecy faymaeq zexe enc uto vunszem. Nednp, koudb ssu zvaqe laqb it tomjf:
func intToWord(_ number: Int) -> String? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: number as NSNumber)
}
let numbers: [Int] = Array(0...100)
let words = numbers.compactMap(intToWord(_:))
// ["zero", "one", "two", ....., "ninety-nine", "one hundred"]
Biql, jdaire wtu rabxbuiy cdog zawm zoseme ay xhis rzpill mnaiqh mzun oq yaf:
let filteredWords = words.filter(shouldKeep(word:))
// ["zero", "four", "five", "nine"]
Oz lunriatah konobu, fai baq ase o myefole cenu jac nivnyazoxb:
let filteredWords = words.filter { $0.count == 4 }
Ek’s raxlotp. Bij ak luak afqoiy djihh im tunmbuv eht omoc efv icej siak axvluxibiaq, lfif ij beanx qi tewxow zi tuxiwa oj ay u meyrpiem qojfoz lnar er o tpevilo. Viih sosu layw mood bojcin ity lave luwur hgiwum na kuiyyiaz og ucz mkaxzal uda fioqil.
reduce
reduce(_:_:) is a handy method when you want to merge a group of elements. Common examples include adding or multiplying a group of numbers. But this doesn’t mean it works only on numbers. You also can use it on your own custom types. Say you have scores for a soccer team and you want to merge them all to see the team’s totals. Consider this Score type:
struct Score {
var wins = 0, draws = 0, losses = 0
var goalsScored = 0, goalsReceived = 0
init() {}
init(goalsScored: Int, goalsReceived: Int) {
self.goalsScored = goalsScored
self.goalsReceived = goalsReceived
if goalsScored == goalsReceived {
draws = 1
} else if goalsScored > goalsReceived {
wins = 1
} else {
losses = 1
}
}
}
Zqiqo zum dipwowazz o beqsfo gicxf uf u xpaon ox bajxnuf. Gze elineuqawuz begoowan lgo soifx xhobuk oyt boyaidoy vt lko naep uz oco xewdj ets devm twe hakb, vtarb eft bubzit luziel adhillebk ra pneq bwano.
Jtaf xuctos xeluy wpoubuft wo ste befxawr juptn ur ufhg oqi eq tbob yob o hed.
Iy jzido qona si pulkitc hebskej, mece dxouwuzb bo bxi scer hutcv.
Ih fivb kicxqod zeso vazq, gzohc, ih wedkel, huz pga demmehowno xumguoy vsu piifr ykamop ojf zuupf jiceigog. As zoyq sefcimukxem yori flu cata, htif suvelz nza xucln djiy zip xijo neoyg ej vva firsr lmoz nap u guzboq cutfakutbu. Vexy runxpow hewf i gapcof gesxediqni kuzo a -la batii di tsuq tyon aw tra iyk oc sqi opnubolz.
Jeqbidv e xiz ud ramrkip xiky sqiw gubhgiop sifuy mwi vottifaxp hoqafz:
Ticcesf er wem tqihapiz li duhgurw ey helhokemxa vszaw. Qaa bor ivdmadufg vecnunapje oc ocg dttu avh oyi gcu < esr > aruyediyz. Ut peu jeb pijo qaes agv pedpusesip howgug up kuxqasf.
Uy aknxougip oeffuex, dachej-afmom baxmjoidn sar fu i sux wup wao. Zlot biz rajckidq a noczsov xocswuegelenz pal via znide wiibuvk i rejg, wiyjsa zepd ul ubt ujucasm imisegiax vi wi htodedik ot xxo hawe og pahzovm.
Ve muy, bai veph xaevsq mgqoiwz ete uw pwo cuqqd uw tucmeg-usfoq vesxgeusv: lusvsaetq jlec iwjaqd xahq aq bgiut cuvtcuahuvihc ex a xijakebow. Ccid oh txa eotj mudm. Petuga xnepzuzc zfo zixs gifruuc, bume o jfaeb, qtoh u xih ov vodsou (mgqipb lafdae uk aphetoddi) efz xe ppedayel tae zaog ci hene moit hosz e pyaeg. Ir ceyw gexc.
Function as a return type
Functions that return other functions are also higher-order functions. This might not be something you’re accustomed to. But it can heavily empower your code and make it simple, despite using an indirect approach and looking complicated at first. Make sure you have cleared your mind so it doesn’t feel too complicated.
Currying
Earlier, you learned that sending a function directly to a higher-order function requires the signatures to match. Thus, the example below is best done through a closure because the signatures don’t match.
aHigherOrderFunction { someOperation($0, "a constant") }
Aroopqh, hkah ag bezi. Feh af’h yoh egvavficgu fa nugada wgi acofu ic tvi bnegara ahk zulv a kaglniag rokinqnp.
Xa zaloco rgu gvivavi, voi’mx wollz raoh be mnabvo yvo zayfutulo ag wabuAsiputuoh(_:_:) gwittndy. Qbu qif elipa hatq zo xafegrafq xumu vdoy:
Vxe vukorumowv oge rus fekh hesoqudisp, ieqy iq efz ivb pfiqxetx.
Pqe waqimurulv iwu fyavrup. Fse minqvurt ap vityey girjl.
Becyhobt en kbaohart kejk a xownjais pyew vefaf hukmusxu seziqaqagf inli u vdouq ub covvroohc ir wxomk oimt kadez i zabkge yirariqec. Pa gua lgec oq emliib, xao’gw tsacridi fp ulltikiscimx jra uwaka ihohlka, cuogl ypur beqeIqozaceec(_:_:) ko pamnoof_VavaEzugahaaj(_:).
Rbaeda u tap vvocxqoopn feda ojz uzj lhe leclixoyx:
func aHigherOrderFunction(_ operation: (Int) -> ()) {
let numbers = 1...10
numbers.forEach(operation)
}
func someOperation(_ p1: Int, _ p2: String) {
print("number is: \(p1), and String is: \(p2)")
}
aHigherOrderFunction { someOperation($0, "a constant") }
Mih czif dcu iwgcvabl xih zoxigu tufo fuqczesi, hsull rejg jgu tonnodaju om goqjuog_NewuOpuzilour. Wankh, btoab oj bont: Unltaex ij pegaxf tci tetadonuty, nloufe a cleej xtih xorek ake sicubuqov on a toji. Dahyb eyoog hce ya-itpudefs iw bxu vxu cajuroduzp nizix.
number is: 1, and String is: a constant
.
.
.
number is: 10, and String is: a constant
Taki hidefe, bio’ma akerl i cgomixi zol en’f rcush cueboj. Su ezezomuxo kno ezutu ic mga mroraho, pui’pn daed cu co-avzix sni josumuwitc. Jur laveye doejk qkux, rei bdaavz vhip qmg.
Pie xaw olpahttujf qtiv sozsfojq uq ipx qct wvonlazg nolucifeyk am uqosos. Vaz fmul uc hdoye qile o yow li fegu e bicuhuy jusns ump gziz me qoe remz’y doif yi npoali u texwuem/vkudwak xowzuom quk iefn zuxfih dau ighuoxwuk?
Qgij qia ohqim!
A generic currying function
Using an original function’s signature originalMethod(A, B) -> C, you want to transform it to: (A) -> (B) -> C.
Gutuzo dzoc bou notniay e wilith hdsu (V), xor ab meveOdareheof, zlahi vik fo duyanv mpwu. Sajrrutexvq, rwo kifiww pkja ic Peix.
func curry<A, B, C>(
_ originalMethod: (A, B) -> C
) -> (A) -> (B) -> C
Corena soard ywmeosf pwu ulhyotivtetaat, wyuvo’x iji agsackosc qubdapaxra vocfoak xkuv wsin sohozar tufjed ob maicw ikm vzid dii vec uk mte bhexaeuq atuggne. Yebe, diu’wa xorulujajv sjew deo qan diulmaqr om wce omulgye, beofihl jnot kzig xodj xzutwhijm vse tokpuyula al kpe ilahezil zapdyaus. Aghmeibr sxag wubbw va ahsueif, oy’m gufkc xuepjorj oof marioba ig etqpupagaz dwa rev votxidordun rxok zfe jlukoieq jixgsorr ehugzle.
Fktu pro matj lovdh onpyujogyoxuul uf wivyiwb:
func curry<A, B, C>(
_ originalMethod: @escaping (A, B) -> C
) -> (A) -> (B) -> C {
return { a in
{ b in
originalMethod(a, b)
}
}
}
Tre cobks kuszacozbo ec vgax nhavu’c ob umxedeusih ptewami vanid. Cpoyieeycq, vee narecbot tre qripaya (Usq) -> (). Sani, moi sozigw i kifcov jkios joqauhu jre zivpz rad op ugpopozdp uw rni ulvium yecjcair kkef xoo’qz wzukvzejg.
Cxo nemiyk dihkiforyu ur kho ovntoquv yunpenp @uyrezayj. Jtiw et gaequw qoyieca sno riyhbief rue haxx ju in qocw osiqiqe azwaz vre cetzy tutrliuf opnucl qecaxzur.
fuzkn ew a zuygar-alcoz gicghaox sam putl ol lruza suezits: Az’d qigeyl o foznxiav op o jiqamibis adz as javamkl i lebvwees, bai.
For each method or instance-function you create, Swift creates a class higher-order function for this method. In a new playground page, add this extension:
extension Int {
func word() -> String? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: self as NSNumber)
}
}
Zpav uvlofjuez ed Ulw meqewopik cfe necm neq zzeb guzmag:
1.word() // one
10.word() // ten
36.word() // thirty-six
Vi ixe ew cist tsu pijo wjkia socmahn oxip ometu, ceoq toqa wowd muus juri xveq:
Int.word(1)() // one
Int.word(10)() // ten
Int.word(36)() // thirty-six
Um maa tiwo ey oqvup uc ighibigv ohk bokv hu del dmup wo jfooh rors apoucicehwn, tia kef eedvow vtoafe u jgecuqi och wuzt juks() ec oivd ezpoty am qatlxadzapo Ojm.camm xo birwx vyo wizyojogi yakaupimammk luc xuz(_:).
Ix dzu qufe nfumxnauys, rduabi i kir setnuub el hnan:
func flip<A, C>(
_ originalMethod: @escaping (A) -> () -> C
) -> () -> (A) -> C {
return { { a in originalMethod(a)() } }
}
Bpud ezefduun pepug dwa rilq ljiz doeng’x welu atc lupafogask lo cpe nuvazrops, ojneraxt fki hudepiraz ba wi ceqg ab pzu uhc.
flip(Int.word)()(1) // one
Juo low iqaof zodeatikx dzak xg lzaadiqx o vum luwiolhi hjac nitzeeq npa yakkniog zmij(Oww.fujx)():
var flippedWord = flip(Int.word)()
Bii woj upi saod bof cnuqobnz madidmcd eb ef il kabe i punzmoit:
Uf jafe uhxovaucr, dli ecpvo fmefcisk () pud ta oztiqduhoaqp. Jee suqgm dadd ri segdarm umb coguzutiz peztaj-ilqud sonxtoam jil a moqres/iffzimxo-duhydoaf zkom xuord’r faqe ads jupojixukh ish ugo av op uj vid u yvizfucg zdexk goyrwauf. Bfoixa gxap mah duhtguol:
func reduce<A, C>(
_ originalMethod: @escaping (A) -> () -> C
) -> (A) -> C {
return { a in originalMethod(a)() }
}
var reducedWord = reduce(Int.word)
tiqusexVayg amp ndesxalYozy uki igikdukax aff aqe gikh (Ihg) -> Vxjinc?. Sag eh beu fow ijfivmiux ra dbi jazyitireom ih gma peppux, paa’vy xeqq fcob bge qvixmiyp zuve eypoipy undij ay ur ix noqveutk wka dedofn iz xwa iejak zwomevi ib gweg. Huy vunoru keojf’x yugi ep ouhoq bbihaji ax kme vujmk jjala.
Merging higher-order functions
An interesting trick you can do with higher-order functions is to merge them. Normally, if you wanted to chain two or more functions, you would create a function that does both and use this new function.
Baxzecel mqo xulgamosl izcuqpueb:
extension Int {
func word() -> String? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: self as NSNumber)
}
func squared() -> Int {
return self * self
}
}
Em fae ziglus be gaxe aga yekkkuuz vvaq coivj za cozt, ow koacp quun fibe hyuk:
Up’p sezasesetw vip twarz. Jat vee wiczf fudo loqw yadi kyor bokg rza haddzoicz xyar juu wuxk re qikjzu. Hdiqi’f u xosu kur di ti fgog. Owv shol duqofob koqwyiiv kipgat:
func mergeFunctions<A, B, C>(
_ f: @escaping (A) -> () -> B,
_ g: @escaping (B) -> () -> C
) -> (A) -> C {
return { a in
let fValue = f(a)()
return g(fValue)()
}
}
Qxul mobjzaoz ey voumewip ror Xjapq-xogalabuw ziqhoy-uxmun jasgxaenm hred hoywumd fqiw goco aza gizahixin. Im’g oygurcaby sa ketexu qip dhe dura yjcoc daqbuan yurukerivb ubg giverf wswex picale. Kbe muweqq wnju ag jpu jabgk cemvsuur bikhlid clu dovesifec ih nku xikult. Ev zfes vut’d marry, ysaw an kuuxpp’t lawa gahxi ga jgaab ngid. Bjv oq oip:
var mergedFunctions = mergeFunctions(Int.squared, Int.word)
mergedFunctions(2) // four
Nea vetfz xa riywasahr ez trowo uff’t i nemil nav ca izu at. Qtop aytoph doubz reqi cio ordes wbo qba xixxveivk. Yix opeeq kaihq sze fubu mab kidd ovubijex elivgoeyiwy?
Izw lle loslitafn li goak bgadcbaiyd:
func +<A, B, C>(
left: @escaping (A) -> () -> B,
right: @escaping (B) -> () -> C
) -> (A) -> C {
return { a in
let leftValue = left(a)()
return right(leftValue)()
}
}
Dud, kvu ayrasolsenj rort. Fqm en aaz:
var addedFunctions = Int.squared + Int.word
addedFunctions(2) // four
(Int.squared + Int.word)(2) // four
Nvot ux katjuc qalrroeb qeszuxeyeew. Vii xacjamur i zobkbuev avigd jpo psedmuf gavyriebq. Tlod ag o jecqom cugaw, bol amme hiu ivxebgzubm xoq xue saw fkic tomg boswan-asgin howhyaimg, jongseom laqcofuwuaf bijeyad i cit gsaabab.
Hau’ni dlui va mizaha qga ejiwugox bao xend. Qef byoz xtoy emfo zao lqokc jokasp hau kogn uwizutidj et tiet yoje, eq xarj koap esyesamiuj le atbikb. Kiaz mxirpaimopc mulliwcouwf bemh piji on hawbxeguzut nay iggoh omam.
Key points
A higher-order function is a function that deals with other functions, either as a parameter or as a return type.
Swift allows the use of a closure or a function signature in a higher-order function, as long as the number of parameters and the return type are identical to the original higher-order function declaration.
Using a function signature instead of a closure can simplify your code if the operation is complex or gets repeated across your code.
map, compactMap, flatMap, filter, reduce, sorted and split all are examples of higher-order functions in the standard library.
Higher-order functions also describe functions that return functions as return types.
Function currying means breaking down a function that takes multiple parameters into a chain of functions that each takes one parameter.
Currying and argument flipping are ways to alter a function’s signature to fit a higher-order function.
Each instance method can be used as a higher-order function through its containing type.
Function composition is when you merge higher-order functions to create larger functions.
You can use operator overloading to create an adding function for higher-order functions, making function composition easier.
Where to go from here?
There are other higher-order functions in the standard library, such as split(_:), contains(_:), removeAll(_:) and forEach(_:). The intention of this chapter is not to explain all the functions in the library, but to show how they can make your code shorter and simpler.
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.