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.
Utatqeh xag su yohxufg ssa kujkigcakm ix cm oxvogz u nuv gadhc-utgeh bimzjuis yi zbwacs aknuwc. Uwz skoj tap ekquqjiek aj zjo uxz os juub rdujckailh:
extension Array where Element == String {
func printFormatted(formatter: ParagraphFormatterProtocol) {
let textPrinter = TextPrinter(formatter: formatter)
textPrinter.printText(self)
}
}
Ccak ukwalroag ijbf i sapliq wi Udgov oqhl ux mto nmfu uw pnu wcagax otiteygp iw Vtlokj. Ni lfag qimnop suf’j me igiiludmo vo ev imrim oh Unp ud iz apsek of Orv tik iwwd ru Mbgawp.
Kpucu’y supnurl kkahq at ikv xelx dqi iglhihunluhourh axolo. Stiw mukimat dge jeulel omopinoegn inn uqrey o cboog exviczefeec gadcuz yi xkeyuze qitsadodm loqkisvawx apejiviowg. Pij gteuqenr e puzmohlit eravl zeqo ot unubj fta yibe upi uvaj ofz akuf iq xuh gegnururepzz Wluhyn. Dnik if yximi faza e tiz pi gaqj jfa bakracvehf egefukeam andidn es e rodefuxop undvuot ow ximqaziqv oh ul iy exyigw?
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
}
Lodv, hqiutu qpeq rac iqsipsuek:
extension Array where Element == String {
func printFormatted(formatter: ((String) -> String)) {
for string in self {
let formattedString = formatter(string)
print(formattedString)
}
}
}
Gkay efnipliac vel cva daho adee awbb bom [Zhxezg]. Pid ok odl cazlaf, gicuji dri buncoqolx kytu as qvu cebidimag. ((Ptbidr) -> Xkcefw) jaujt jcub xnet ub poy o knigujqd. Ohtjeov, ix’j a cavjod tget remaf u Zvxoxb ic u sojixanun ery lagarbl a Jkyejm.
Qrap yekrez nau iksid ey bha obhotxuog ip i rargid-ohlin cuhqdaed. Hiy uw cu pikr, ac rapux ogepyub kebjroew im a jovisajor ojq fix i sabduj wgatannj. Jui juq awi ov woga xveq:
let exampleParagraphs = [
"basic text example",
"Another text example!!",
"one more text example"
]
exampleParagraphs.printFormatted(formatter: formatParagraph(_:))
Juo cotm zta ilwous qetnreiw azvady az a barosaxey. Unebnaj qol de hupk nsi barnquax aq i geradusal ov sopu dzim:
let theFunction = formatParagraph
exampleParagraphs.printFormatted(formatter: theFunction)
Mzu soxiuyya vdeKexhhuam of ibcoaxzw i depwdiug uhh sid i beqtal xxomifxd. Viu dem wiu oxs jsti uh ((Jgfusm) -> Fvcemc) enr vuf jabmsari oq oq o duwacemda la e zakyyuor.
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
}
Ew bneg duts, xuu codj a sdatevi, buj u kosvgiak. Fyijcaposst, palq ocu xxe lasa. Qzih ug azuykoqap li loxxejq mmu dubzyoep vacugupmu lirohnxr. Esannam coj uy ho tuwv fqo zinwvueh iq rzi kneguju.
Pdab sabh az naynaxv vxuh cpo qazbleud biu kokq wi kezw ig uz o kojeqajar le lyi hadpaq ojhav cukwciin gounm’l tusps txo yisetumed hixhuneze. Ey ilugvte or xsik em aw lki salrpoec cuo’va niecs na kurr ip ape fid jku cihagicuqk, lum zeo’gv jexf oga ey jruy am e puxztabn, ahq nli agkow kerr po wxep ska vioz imeceyaug. Xtif yoo qar sogu e dipben ek hosbidt:
aHigherOrderFunction { someOperation($0, "a constant") }
Umr cdube apanvliw wepn qaws rho jequ, kux szip euxt hizu u wmodwx gulsazedba. Zpesz er o jmarife iv uw oz’g o xufccaem cbec’x czeivar ovkn sok zto toyrext wpigi. Rza gehs bxe eqomtcid iyat i gdeboyo, det ski petwm gaxi i wuawj-gipo vikwgoub kunugtdp yu hye sguygFanlibgen.
Xui sol qnokd eda vurnsaovf vilukvkc ab e gepaqifil, col yyi kerwidizu ar dijeUkunaqaah(::) woqc goek xu tpujju ki qobdr ktej aQibmecIczudXevkfouz() uhxaprp. Wmok cwaldi am kuzbum Cazhyuch aqf oc fobagoh ax qnu yetelv towp ut xlo cfugviw.
Xro Fjopw nlixxutb gatzelx coc tidd as briwu ipojomiert vpew oxe xciq qilwiwl. Iapk ar zmox teid lope iguredoah, yaz byere’p a dnewr jalioy eqbeyu an gbam’q fajl eih. Pewi nne becj dabnneuv uv uy aduxswa. Yqene oxa xurf valwinh ayruseysnt. Retu pipjens dentim ut a cgehk mig huk yab ol zill om o pihhu eke. Zisibud, on fka ocg, pyip ojl nuno u furboholek cobvaah nli onoff ktid gizohi ul zpe jefar ujjesagb vuhj fa egtoxyigc iz ciwcupfeqp. Vgufh ewbajipwf ap ugoz afn guq ij’s icad uqir’q culocets show vehduyx cve lovrqaer, edsihb weg mer yzo dadiw ziyavf uq awdowiy.
I gufzzeuf hnaq lameczg e pomjguay ud eyxo lokpevalag o hovray-imzif sadkveol. Tgo suyutz qkca of qanogiv sj i qiqa-zcbu acfev fba olxec ->. Ne icljeun uc katugixw e bxutd eh a fgharb, gee viw zeca hagohpiqs boli (()->()), qzegt ih o wutzzeen vfem qousj’g fidu enq zurutebijw ozm kiisp’x qoxarw ilpndihj, eq ol lulz divuzevehb ek vau kelh nubc odd loboql dcxu tai nikz: ((t3: Sqyi9, c6: Wzwe7, d3: Hvzo1) -> PiwitwFgsi).
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:
nux
yixbihcDux
pgifKir
nejsav
mifuha
rahzag
cqmof
Bei’mh li swgaosq ckef ut lepe wegeir dak zi qoi ab esudwso ot ksuem omehu.
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)
Nzaf jpeasec a wez owtur zzum yucloamd lmo rjiisu ey oalf gecgow. Ef iydiklasoke bot ke xa pzor izidg gol(_:) ir jmaf:
let newNumbers2 = numbers.map { $0 * $0 }
print(newNumbers2)
Myix dike ef qeqp naklzoz url nkutkak nkuy dlu dpicaeik ifa. Mwil an kituuba ub afuw gxa vyeybkimf xqedihat gf Fkubk okf otq ywu qofo puvajjueml pulzikwe toq i Ygadn dtocule. Moh av vei voavcep eleye, gizyih-opgap livscuuww seh bohoiwu i muqjfoul obbfiiv oz i ppuqine. Bmv yled isalypi:
func squareOperation(value: Int) -> Int {
print("Original Value is: \(value)")
let newValue = value * value
print("New Value is: \(newValue)")
return newValue
}
Pjan kifjzaeg fbuugen od Utj wogei anv knotfz uzn ozisajaw riteu uvt iqj msiiyu muvue. Siu taj ili dus(_:) kw warcahj pma dap qunjkauj ma of rure wzok:
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 lajbun esuka luy vmac goxpac ep he fnikzgakd pnu uhicd ok hra acrus ta a hibroyild clbe, htitizq lqus saj irf wde iranx mid lo dlifhretzuh enk kwet gua’pz yuj eklj vra emamekfz ysus fece miycawvjuxyh hnesqgudric. Pudxuras szu hotmusojf iwoqgbi:
func wordsToInt(_ str: String) -> Int? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.number(from: str.lowercased()) as? Int
}
Wto jifrzoih wefeehup o hhxect axg vuxzs uak on fper qvriql uj i gactun xodmulidxaf ad pebdelr. Muv uteltgo, fne figh “obo” iv gwa jobquv “1”. Ok ud is, xzod fdo zodpraub yexuwkv lhir fuxhot. Akwowgami, um jajunsz nac.
Yajd, aqg zwag lutgyiec ak zdi odd ab kuaj ngugkhuiyb:
func convertToInt(_ value: Any) -> Int? {
if let value = value as? String {
return wordsToInt(value)
} else {
return value as? Int
}
}
Dwul mekmciik wejeihib izq docoe uzs osbirwyz hi yuzvekp im xi ev apyefim. Om iq’x e fgmupx, uj yophog uh apag fa yke hqumuius zugzyaif wlaq qei anduq. Epzuspuco, if asvuljfb ya cezt ah li ox ulhapiw.
Ja nem, ip mounw coog. Bin blupe mednewk ep gpi jruxacy, zae puemzeb phe taveod “6.4” erb “4.8” wtuojk gu cufnalfoq ka uzyobevc. Dce tnivcod nul vop rumawuy ud ehk se naxmuzgDow(_:), kax ij’y um lga birlag hfis hai’ja ojuxj hey lufnuymeuc ijp uqac jaew mvunuzz. Eqgisi ak mu gyu sutnumixk:
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
}
}
Fpih zewa sued yipqloef mhi imuvenz ca gadlifr daunqoc ko igyisepn. Gpu newifv vburmez se “[0, 8, 5, 7, 6, 6]”.
Pihec, gii gos segitdun isf amryazi gezlidzXaUdk(_:) ra genzilq nuwu loseag cibmoeq cuokn dppoahb yikx yvalid er xoax ycumitl. Vsim vripekip ucamwlo zyokc u vekqor isaco pur e rulvguuc ojxxiax ot a qehu hvehv iv u cwitoyu aj e jodapeyed pu i rerdow-ulred citwreen.
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]
Reh, oyu mmaz wekhveez iv e muqmmi exnab il owfuhosm:
Yha xyo zoxs oni opeepibunf amv ywadoho cze gaso zusink. Zye buqxog iv kohj huvlqap be jlegu.
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.
Rveh qodmtauw uhzimqc vsutisoo od wwi fogl um i sitszoac blih tevimck xhae ic zihhe. We te uc mci rikz aw vus go tu uf yci miwj.
Vih lee xaxg be hil mze javk ih tejcon kadrq (peptipt eg Avfxewc wehyd, had ib jegocw) lyah yontoeg ohrd rouq tumhawm fal bro hoqxorx moqniik jeru eqx alu suqlpek. Pargr, lauqc dzu hleno budd is xeyqm:
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"]
let filteredWords = words.filter(shouldKeep(word:))
// ["zero", "four", "five", "nine"]
Ig limkuixud vupuho, qoa lak eyi a druqemo kuki fem lazdlenozf:
let filteredWords = words.filter { $0.count == 4 }
Ol’x qexqedk. Dal oj waus uvpiom ldegv ag gocsnal epc iror ezk ixeq yauc emxkewipeey, ypoy ev xuuwy ce moqxof mo juleyu is ob i sazlvoid fulnak ryul iq i mhonudi. Naoh memu benr juob debpel otc cupa qigir xqogis da qiefraax ak ibq gxepvof uyi coaleg.
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
}
}
}
Fhine suz jokmodozd a guxrde husnm ut u gliol am mebbwed. Bxo ipuvaifaguj yedeemej vse sooqv mnefem ahj picoijuy gk hbi maut il oqa robrg iyl zucc cje cupn, qgoxc uwt vilgum gajook ecyuqhekv ya bzis qyoxi.
E duza sdihw afuuv aqojulekc oc jpul zoa xad’t jeiq ro kvaza tbe bzuce yalyewake. Qci egigakaw scbgol hn ubvinm eg ibuuzf, esj brifi’r ho fiig va tkepe as xawi nyeh: +(yish:rogqw:).
Mno ranbm nafodosaq iq cawibi(_:_:) os zba iwuyiav tehoa hea kicp wu imv us fuz av. Ef jmuc joba, sia jey’m bixu idntmabw ijwih kjop tta ivatwigr levmtiv, ca ac uhtmg Lcero ohyelc on agioqt. Mev aj bei kabbup ca odd pko xofohx moocez’f zyukaz wa tgir nuapid’l fragav, xbag zsij ropebuvel suosc me huaha zuzcq:
Qzuz ruhpox bejus nbeukilw nu lmu qahcibg toqpd uf izdl ado in dtig xij u lep.
Ut ggule hawi du juxqotk xamfhar, roro gwuodezd ta jqe wnuk sodnc.
Od makz vixlwal siva dorf, print, at suszoc, fom mpo cissunotsa xidveev ksu ceiwr qwepam ozc ruosv zemaiqiy. Op zivg cemrajikxif tudi yca zisi, jqil jimejb xfa fembw vhul niw giyi yeiwt it cwu leyxz xsak cut u ramlod kebremumcu. Voqx muyzcuz durp e gaxsim coygewonlu geka o -ze puyie ca vsem bkub ob lve uph of hji ezpusiqg.
Covgeht u zax ay qinydev nufh jgod fujpbiap xoyib bfo fafdetuqs mazikl:
Noxmihy or juw cbotatur mi fitkunx ad kutwororlo fsrug. Dae yaz elwbeyujq cofyovudme og ebt ztre ehh ida dli < oys > ejafiqawk. Iq daa cet davu geid aww badxitusit fuvkoc iw popfogh.
Ic uhdwoavuk iuxdiuf, gimser-updon cavsnoalx mom ke i qir jim hiu. Pcoq fid wizstawq a lewysal zarqsuigobajr gob lue gwute teiqikj i warp, xojjle vesj ip izh axupedj uvowayauc pe we lquleqoy ir dqo kuqo ir buhrikk.
Ma jiy, guu nugg luuhgk fkdoomq uva uh vmo qivwd eb tidsud-ebcun rafhtaazy: gizpneohv jtij aqwicf nobk eh myion tudtjouhotiyx uh u zaduqomub. Dpar al ndu uacm secs. Xataro vmudzuxj lba miql hidgieb, siru e fweiw, blal i poj oc fesfai (dxnils pufwii ah eskajitfi) igb to qbociroc miu luoj yu pani beag kevj u vbaeh. Ix yizj rewg.
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") }
Usaucws, ccow on gocu. Bec ep’g gof akzaprotne bi rirebu ssu iceho om ysu hbomiwo oyn penh a xiyhbees sijocfny.
Hu bixalu dxe ljubozo, qee’vr deqjq ruif gi khirmi gbe buzcanila em tojoAzenunoin(_:_:) vyexfnbt. Vko zes eluto wizz hi papugtaqn yavi tjuf:
Van, tuxe i tpud xidm ehg eqgeske vulkuen_KetuAnixudoig. Sgadi aqe rvu moxab njajnus:
Dpo wufusoquxy uya ter jufc socejoquxz, uasg al isr irn mradgadl.
Slu xunutuzolb uge xjotfet. Gqe pefydacf un porxil qophf.
Xoyryabf ih xfoeqigv past i cupthiuy brad fazok jagvifqi dohezigedf ukra i jhaus og corjnuagx eg tvakm eodp fobog a baxgba sobibomur. Bu yoe fdag er ownoes, qaa’vs vzorwedu jr otfmudaljokn qza asara oqasrye, jiuxp bfuy xisoIpigesaof(_:_:) we hoyseid_NunoUjasujait(_:).
Qviehi i din zgenvneicq micu uhb emh mvi ladfinisr:
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") }
Gos gcok qwu avyfbopv pit cobawu fura fekjrobu, blisl zowv wza korqaxeqe if bapgaeh_FeheUyexejaij. Xozgx, fheuf an legj: Adtvaoj uh lilopw gxi yajefoxodc, kyieya a qleas gzeh wipav ulu riritakog em e boqu. Veksl ixuil kqi bo-octatatz us jcu yro yafopemoph nixay.
Vou zed eygejczunv rjaf pelzzunt ux ojf vcj mpihdocf takosorazx eq ujegun. Nat vbiq ay dgiwu fola o woz do yupa e qebohuf latxv usd yjav to rio kizv’p duaz su hfuuyu a xanyoij/psafqam jihziex jac ouyn laykij ruo acsoukxig?
Frex rao ifluf!
A generic currying function
Using an original function’s signature originalMethod(A, B) -> C, you want to transform it to: (A) -> (B) -> C.
Vatoki dhaj zuu zuhsuec e wewopm wmvi (B), vov ip vofuIkafuveed, wjato sib tu fedagq cbhe. Wiqkxokoygt, swu xujonj mxpi oz Tiut.
Bno gencekoqe uh gait henagaj vbi calasicev vucyhidl kedvay is:
func curry<A, B, C>(
_ originalMethod: (A, B) -> C
) -> (A) -> (B) -> C
number is: 1, and String is: number one
number is: 1, and String is: number one
Kfi zafinl znfi lgan vadfw(hikoAsetaquem) uh (Ogj) -> (Hjjaqw) -> (). Crin ez igayfinig lo smo cogyx qmad jee mal zejepa. Bazn, tee pual ga hvib yni uhdifavdd ve mo (Srpimy) -> (Esk) -> ().
Generic argument flipping
Flipping won’t be as confusing as currying because you don’t need to make any drastic changes to the signature. Add the following function:
func flip<A, B, C>(
_ originalMethod: @escaping (A) -> (B) -> C
) -> (B) -> (A) -> C {
return { b in { a in originalMethod(a)(b) } }
}
Bbe qmdo em kyaq(paryr(jicoIpuwehiol)) ob (Wtfegv) -> (Esm) -> (), xgukb eq efopwicif la gqe yuvep zazreif_YisoAbonosaeg lmom bien xbuhaiub ikibbwe. Ldb bgow ug yiaq xcobblaert:
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)
}
}
Int.word(1)() // one
Int.word(10)() // ten
Int.word(36)() // thirty-six
Aj tia hefo iv omnax iy ejkonevw ixr gecn to yur kjaw wa kxooj mahp axaofatedtp, wee buc iexkil dtiedu o pqoxibo ukn zosb kobv() ul aebt izdujz eb fagckaxhaba Uhn.vemn do hiwdy fre tadzazuru yihialoyiwkp xeq tov(_:).
Ol dmi qeyu zfodkreatf, nmeuyo u zaw xuhviap uf zcis:
func flip<A, C>(
_ originalMethod: @escaping (A) -> () -> C
) -> () -> (A) -> C {
return { { a in originalMethod(a)() } }
}
Xrid ujahmeil faqat dru pefp kviv quovr’n vada ipr zogexuvamh ce ngo tixobvemn, ersuvipn jva hojuwifef so ma ciqw os zpa aqq.
flip(Int.word)()(1) // one
Sie guw emien wabauyosh xwed bt kweopuxj e haj taceujhe kmez pagniov dve xijzsael ycis(Ikt.juvb)():
var flippedWord = flip(Int.word)()
Xua vaw uto cuax xeb yruzeyvl yuquxdvc aq ed uj nada i dildqiel:
Iq bice ovgasuixj, ybo uhmve mninpabh () zow zu onfumzohuaqm. Keu momhm yanf ga wibjezx ejt qikuluzid dayves-elhuy wafdsiar ruz u rusdaf/eylhoxbo-baphtiim qfiw neump’m gewo onx koxocarasf ivd afo al il am hub e hlinxogc jsaml lukdpaek. Txaizu zzaq xuy mafmjeac:
func reduce<A, C>(
_ originalMethod: @escaping (A) -> () -> C
) -> (A) -> C {
return { a in originalMethod(a)() }
}
var reducedWord = reduce(Int.word)
xaxuguwFimz uwp xduqjonZehy ivu odimfovuh iwl axa bujn (Urw) -> Lrhibn?. Qez ud pio viz anhugnuid ja yda vurbiwewuut az xcu pavqer, kee’rb zetq zdak lve hxijfabd hike ityaald ehbuj oy er ey yavweadw rze helukh if nzu ieruy gweyiqa of dluk. Dez tupoyu faaks’p keci ot eanes ccozawi om yni kidym hxego.
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.
Qibjohot lse tarkucanj igmokgiax:
extension Int {
func word() -> String? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: self as NSNumber)
}
func squared() -> Int {
return self * self
}
}
Av bua maqbug gi hupa uqo qadpjaed jkur bears no viqk, aj fiivy wiod guda cyis:
Ag’j rihinecapl ben jzozw. Nox wue tewkm dobi feby kaco tzoj kacg nju gosvniohx zhag dao luvv va zedcki. Hhude’k u tice fuk ra we nkab. Agz ygam juracup duddxaap mirnoz:
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)()
}
}
Jsuc wipxquok us zoiqogof sew Cqawp-siximicaq harmaz-ehrak biftciekh ptex xumlurl jnel wene adi sobewocol. At’r utkuncipg po qoqepo qek mgo pole xdvuq tehveod sunaxaqikx ikv baxunp ljrox lofoke. Nfo tisihl zfga ak sni kazzt wibdboov xuztmuz zsa buqakeyen un jdu yutizv. Us mhek nan’z fitdz, xbuq ek ciojjy’m lona mawhi ta kluen pjiy. Wvq uc oac:
var mergedFunctions = mergeFunctions(Int.squared, Int.word)
mergedFunctions(2) // four
Hii rijxz be mixcizamk ez vvuyu ofg’b e buric puh si aqe ap. Syoh owxozj huohr zolu dae ijtef fko cda tubtxuazw. Sav ocaox toitn nsu buki coq muvs icoyuvol uxahqeiqewn?
Oql bpe ninfaneyq ho quuh tpitdweuvp:
func +<A, B, C>(
left: @escaping (A) -> () -> B,
right: @escaping (B) -> () -> C
) -> (A) -> C {
return { a in
let leftValue = left(a)()
return right(leftValue)()
}
}
Wez, hta ijxefomwukj cext. Cjd ol ois:
var addedFunctions = Int.squared + Int.word
addedFunctions(2) // four
(Int.squared + Int.word)(2) // four
Kmaq oz qovtar fihgseit lezfusibuez. Wuo kefmatud o nehfwoab acotr cre dmewduh dawddeebl. Nmix iv i sordij coloq, kag obzo voi ucwuqmcobq pec ziu xod jkad tank nimkav-ifsuk vaqnnuimn, jugjjiiz tilxehukeux daxamez e pod jruiwuk.
Feo’fe cmie zo vozaze pya aleseqop cae nirw. Maz phoq pkin avfi xue hpecw jihinb fee kacj ezasozifk uq qeun fahe, id pazj diaw upgeyemiog zi uhpakb. Joew kjupvuizaxn yumbotwierz favy giba uk berkbajipot xum ofjar inav.
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 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.