SlideShare a Scribd company logo
1 of 40
Download to read offline
SOLVING CALLBACK HELL
WITH GOOD OLD FUNCTION COMPOSITION
Vincent Pradeilles (@v_pradeilles) – Worldline
CALLBACK
HELL?
CALLBACK HELL?
typealias CompletionHandler<Result> = (Result?, Error?) -> Void
func service1(_ completionHandler: CompletionHandler<Int>) {
completionHandler(42)
}
func service2(arg: Int, _ completionHandler: CompletionHandler<String>) {
completionHandler("Result: (arg)")
}
func service3(arg: String, _ completionHandler: CompletionHandler<String>) {
completionHandler("
!
(arg)")
}
CALLBACK HELL?
typealias CompletionHandler<Result> = (Result?, Error?) -> Void
func service1(_ completionHandler: CompletionHandler<Int>) {
completionHandler(42)
}
func service2(arg: Int, _ completionHandler: CompletionHandler<String>) {
completionHandler("Result: (arg)")
}
func service3(arg: String, _ completionHandler: CompletionHandler<String>) {
completionHandler("
!
(arg)")
}
CALLBACK HELL?
typealias CompletionHandler<Result> = (Result?, Error?) -> Void
func service1(_ completionHandler: CompletionHandler<Int>) {
completionHandler(42)
}
func service2(arg: Int, _ completionHandler: CompletionHandler<String>) {
completionHandler("Result: (arg)")
}
func service3(arg: String, _ completionHandler: CompletionHandler<String>) {
completionHandler("
!
(arg)")
}
CALLBACK HELL?
typealias CompletionHandler<Result> = (Result?, Error?) -> Void
func service1(_ completionHandler: CompletionHandler<Int>) {
completionHandler(42)
}
func service2(arg: Int, _ completionHandler: CompletionHandler<String>) {
completionHandler("Result: (arg)")
}
func service3(arg: String, _ completionHandler: CompletionHandler<String>) {
completionHandler("
!
(arg)")
}
CALLBACK HELL?
typealias CompletionHandler<Result> = (Result?, Error?) -> Void
func service1(_ completionHandler: CompletionHandler<Int>) {
completionHandler(42)
}
func service2(arg: Int, _ completionHandler: CompletionHandler<String>) {
completionHandler("Result: (arg)")
}
func service3(arg: String, _ completionHandler: CompletionHandler<String>) {
completionHandler("
!
(arg)")
}
service1 { result, _ in
guard let result = result else { return }
service2(arg: result, { result, _ in
guard let result = result else { return }
service3(arg: result, { result, _ in
guard let result = result else { return }
print(result) // Result: 42
})
})
}
!
infix operator ~>: MultiplicationPrecedence
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ second: @escaping (T, CompletionHandler<U>) -> Void)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ firstResult, error in
guard let firstResult = firstResult else { completion(nil, error); return }
second(firstResult, { secondResult, error in
completion(secondResult, error)
})
})
}
}
let chainedServices = service1 ~> service2 ~> service3
chainedServices({ result, _ in
guard let result = result else { return }
print(result) //
!
Result: 42
})
let chainedServices = service1 ~> service2 ~> service3
chainedServices({ result, _ in
guard let result = result else { return }
print(result) //
!
Result: 42
})
CALLBACK HELL
SOLVED!
REALLY?
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void,
_ transform: @escaping (T) -> U)
-> (CompletionHandler<U>) -> Void {
return { completion in
first({ result, error in
guard let result = result else { completion(nil, error); return }
completion(transform(result), nil)
})
}
}
let chainedWithMap = service1
~> { int in return String(int / 2) }
~> service3
chainedWithMap({ result, _ in
guard let result = result else { return }
print(result) // Prints: 21
})
let chainedWithMap = service1
~> { int in return String(int / 2) }
~> service3
chainedWithMap({ result, _ in
guard let result = result else { return }
print(result) // Prints: 21
})
!
!

More Related Content

What's hot

Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8RichardWarburton
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerMario Fusco
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Chang W. Doh
 
C interview question answer 2
C interview question answer 2C interview question answer 2
C interview question answer 2Amit Kapoor
 
The Ring programming language version 1.5.2 book - Part 31 of 181
The Ring programming language version 1.5.2 book - Part 31 of 181The Ring programming language version 1.5.2 book - Part 31 of 181
The Ring programming language version 1.5.2 book - Part 31 of 181Mahmoud Samir Fayed
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
The Ring programming language version 1.3 book - Part 18 of 88
The Ring programming language version 1.3 book - Part 18 of 88The Ring programming language version 1.3 book - Part 18 of 88
The Ring programming language version 1.3 book - Part 18 of 88Mahmoud Samir Fayed
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
Programming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAYProgramming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAYvikram mahendra
 
GeoGebra JavaScript CheatSheet
GeoGebra JavaScript CheatSheetGeoGebra JavaScript CheatSheet
GeoGebra JavaScript CheatSheetJose Perez
 
The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210Mahmoud Samir Fayed
 
Hey Kotlin, How it works?
Hey Kotlin, How it works?Hey Kotlin, How it works?
Hey Kotlin, How it works?Chang W. Doh
 
The Ring programming language version 1.5.4 book - Part 32 of 185
The Ring programming language version 1.5.4 book - Part 32 of 185The Ring programming language version 1.5.4 book - Part 32 of 185
The Ring programming language version 1.5.4 book - Part 32 of 185Mahmoud Samir Fayed
 
Data structures stacks
Data structures   stacksData structures   stacks
Data structures stacksmaamir farooq
 
The Ring programming language version 1.3 book - Part 23 of 88
The Ring programming language version 1.3 book - Part 23 of 88The Ring programming language version 1.3 book - Part 23 of 88
The Ring programming language version 1.3 book - Part 23 of 88Mahmoud Samir Fayed
 
C++ Lambda and concurrency
C++ Lambda and concurrencyC++ Lambda and concurrency
C++ Lambda and concurrency명신 김
 
The Ring programming language version 1.5.3 book - Part 35 of 184
The Ring programming language version 1.5.3 book - Part 35 of 184The Ring programming language version 1.5.3 book - Part 35 of 184
The Ring programming language version 1.5.3 book - Part 35 of 184Mahmoud Samir Fayed
 

What's hot (20)

Fp201 unit5 1
Fp201 unit5 1Fp201 unit5 1
Fp201 unit5 1
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better Programmer
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요
 
C interview question answer 2
C interview question answer 2C interview question answer 2
C interview question answer 2
 
The Ring programming language version 1.5.2 book - Part 31 of 181
The Ring programming language version 1.5.2 book - Part 31 of 181The Ring programming language version 1.5.2 book - Part 31 of 181
The Ring programming language version 1.5.2 book - Part 31 of 181
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
The Ring programming language version 1.3 book - Part 18 of 88
The Ring programming language version 1.3 book - Part 18 of 88The Ring programming language version 1.3 book - Part 18 of 88
The Ring programming language version 1.3 book - Part 18 of 88
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Programming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAYProgramming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAY
 
GeoGebra JavaScript CheatSheet
GeoGebra JavaScript CheatSheetGeoGebra JavaScript CheatSheet
GeoGebra JavaScript CheatSheet
 
The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210
 
Hey Kotlin, How it works?
Hey Kotlin, How it works?Hey Kotlin, How it works?
Hey Kotlin, How it works?
 
The Ring programming language version 1.5.4 book - Part 32 of 185
The Ring programming language version 1.5.4 book - Part 32 of 185The Ring programming language version 1.5.4 book - Part 32 of 185
The Ring programming language version 1.5.4 book - Part 32 of 185
 
Data structures stacks
Data structures   stacksData structures   stacks
Data structures stacks
 
The Ring programming language version 1.3 book - Part 23 of 88
The Ring programming language version 1.3 book - Part 23 of 88The Ring programming language version 1.3 book - Part 23 of 88
The Ring programming language version 1.3 book - Part 23 of 88
 
C++ Lambda and concurrency
C++ Lambda and concurrencyC++ Lambda and concurrency
C++ Lambda and concurrency
 
The Ring programming language version 1.5.3 book - Part 35 of 184
The Ring programming language version 1.5.3 book - Part 35 of 184The Ring programming language version 1.5.3 book - Part 35 of 184
The Ring programming language version 1.5.3 book - Part 35 of 184
 
Golang dot-testing
Golang dot-testingGolang dot-testing
Golang dot-testing
 
Oopppp
OoppppOopppp
Oopppp
 

Similar to Solving callback hell with good old function composition

Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Alex Semin
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Codemotion
 
I wrote the following change it to having a header, main and cpp fi.pdf
I wrote the following change it to having a header, main and cpp fi.pdfI wrote the following change it to having a header, main and cpp fi.pdf
I wrote the following change it to having a header, main and cpp fi.pdfrishteygallery
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기진성 오
 
The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPathsVincent Pradeilles
 
Swift 3.0 の新しい機能(のうちの9つ)
Swift 3.0 の新しい機能(のうちの9つ)Swift 3.0 の新しい機能(のうちの9つ)
Swift 3.0 の新しい機能(のうちの9つ)Tomohiro Kumagai
 
Compiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionCompiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionEelco Visser
 
Project_Euler_No_104_Pandigital_Fibonacci_ends
Project_Euler_No_104_Pandigital_Fibonacci_endsProject_Euler_No_104_Pandigital_Fibonacci_ends
Project_Euler_No_104_Pandigital_Fibonacci_ends? ?
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kirill Rozov
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Mario Fusco
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For GoogleEleanor McHugh
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order functionChiwon Song
 
Monadic Comprehensions and Functional Composition with Query Expressions
Monadic Comprehensions and Functional Composition with Query ExpressionsMonadic Comprehensions and Functional Composition with Query Expressions
Monadic Comprehensions and Functional Composition with Query ExpressionsChris Eargle
 
Swift the implicit parts
Swift the implicit partsSwift the implicit parts
Swift the implicit partsMaxim Zaks
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsEelco Visser
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
 

Similar to Solving callback hell with good old function composition (20)

Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
I wrote the following change it to having a header, main and cpp fi.pdf
I wrote the following change it to having a header, main and cpp fi.pdfI wrote the following change it to having a header, main and cpp fi.pdf
I wrote the following change it to having a header, main and cpp fi.pdf
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPaths
 
Swift 3.0 の新しい機能(のうちの9つ)
Swift 3.0 の新しい機能(のうちの9つ)Swift 3.0 の新しい機能(のうちの9つ)
Swift 3.0 の新しい機能(のうちの9つ)
 
Compiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint ResolutionCompiler Construction | Lecture 9 | Constraint Resolution
Compiler Construction | Lecture 9 | Constraint Resolution
 
Project_Euler_No_104_Pandigital_Fibonacci_ends
Project_Euler_No_104_Pandigital_Fibonacci_endsProject_Euler_No_104_Pandigital_Fibonacci_ends
Project_Euler_No_104_Pandigital_Fibonacci_ends
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
 
Simpler java
Simpler javaSimpler java
Simpler java
 
Monadic Comprehensions and Functional Composition with Query Expressions
Monadic Comprehensions and Functional Composition with Query ExpressionsMonadic Comprehensions and Functional Composition with Query Expressions
Monadic Comprehensions and Functional Composition with Query Expressions
 
Monads in Swift
Monads in SwiftMonads in Swift
Monads in Swift
 
Swift the implicit parts
Swift the implicit partsSwift the implicit parts
Swift the implicit parts
 
Intro to Pig UDF
Intro to Pig UDFIntro to Pig UDF
Intro to Pig UDF
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 

More from Vincent Pradeilles

Taking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryTaking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryVincent Pradeilles
 
How to build a debug view almost for free
How to build a debug view almost for freeHow to build a debug view almost for free
How to build a debug view almost for freeVincent Pradeilles
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testingVincent Pradeilles
 
Implementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional ProgramingImplementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional ProgramingVincent Pradeilles
 
Property Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaProperty Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaVincent Pradeilles
 
Advanced functional programing in Swift
Advanced functional programing in SwiftAdvanced functional programing in Swift
Advanced functional programing in SwiftVincent Pradeilles
 

More from Vincent Pradeilles (8)

On-Boarding New Engineers
On-Boarding New EngineersOn-Boarding New Engineers
On-Boarding New Engineers
 
Taking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with SourceryTaking the boilerplate out of your tests with Sourcery
Taking the boilerplate out of your tests with Sourcery
 
How to build a debug view almost for free
How to build a debug view almost for freeHow to build a debug view almost for free
How to build a debug view almost for free
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
 
Implementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional ProgramingImplementing pseudo-keywords through Functional Programing
Implementing pseudo-keywords through Functional Programing
 
Property Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaProperty Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become Java
 
Cocoa heads 09112017
Cocoa heads 09112017Cocoa heads 09112017
Cocoa heads 09112017
 
Advanced functional programing in Swift
Advanced functional programing in SwiftAdvanced functional programing in Swift
Advanced functional programing in Swift
 

Recently uploaded

The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfayushiqss
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456KiaraTiradoMicha
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024Mind IT Systems
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 

Recently uploaded (20)

The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 

Solving callback hell with good old function composition

  • 1. SOLVING CALLBACK HELL WITH GOOD OLD FUNCTION COMPOSITION Vincent Pradeilles (@v_pradeilles) – Worldline
  • 3. CALLBACK HELL? typealias CompletionHandler<Result> = (Result?, Error?) -> Void func service1(_ completionHandler: CompletionHandler<Int>) { completionHandler(42) } func service2(arg: Int, _ completionHandler: CompletionHandler<String>) { completionHandler("Result: (arg)") } func service3(arg: String, _ completionHandler: CompletionHandler<String>) { completionHandler(" ! (arg)") }
  • 4. CALLBACK HELL? typealias CompletionHandler<Result> = (Result?, Error?) -> Void func service1(_ completionHandler: CompletionHandler<Int>) { completionHandler(42) } func service2(arg: Int, _ completionHandler: CompletionHandler<String>) { completionHandler("Result: (arg)") } func service3(arg: String, _ completionHandler: CompletionHandler<String>) { completionHandler(" ! (arg)") }
  • 5. CALLBACK HELL? typealias CompletionHandler<Result> = (Result?, Error?) -> Void func service1(_ completionHandler: CompletionHandler<Int>) { completionHandler(42) } func service2(arg: Int, _ completionHandler: CompletionHandler<String>) { completionHandler("Result: (arg)") } func service3(arg: String, _ completionHandler: CompletionHandler<String>) { completionHandler(" ! (arg)") }
  • 6. CALLBACK HELL? typealias CompletionHandler<Result> = (Result?, Error?) -> Void func service1(_ completionHandler: CompletionHandler<Int>) { completionHandler(42) } func service2(arg: Int, _ completionHandler: CompletionHandler<String>) { completionHandler("Result: (arg)") } func service3(arg: String, _ completionHandler: CompletionHandler<String>) { completionHandler(" ! (arg)") }
  • 7. CALLBACK HELL? typealias CompletionHandler<Result> = (Result?, Error?) -> Void func service1(_ completionHandler: CompletionHandler<Int>) { completionHandler(42) } func service2(arg: Int, _ completionHandler: CompletionHandler<String>) { completionHandler("Result: (arg)") } func service3(arg: String, _ completionHandler: CompletionHandler<String>) { completionHandler(" ! (arg)") }
  • 8. service1 { result, _ in guard let result = result else { return } service2(arg: result, { result, _ in guard let result = result else { return } service3(arg: result, { result, _ in guard let result = result else { return } print(result) // Result: 42 }) }) }
  • 9. !
  • 10.
  • 11.
  • 12. infix operator ~>: MultiplicationPrecedence
  • 13. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 14. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 15. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 16. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 17. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 18. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 19. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 20. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 21. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 22. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 23. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ second: @escaping (T, CompletionHandler<U>) -> Void) -> (CompletionHandler<U>) -> Void { return { completion in first({ firstResult, error in guard let firstResult = firstResult else { completion(nil, error); return } second(firstResult, { secondResult, error in completion(secondResult, error) }) }) } }
  • 24. let chainedServices = service1 ~> service2 ~> service3 chainedServices({ result, _ in guard let result = result else { return } print(result) // ! Result: 42 })
  • 25. let chainedServices = service1 ~> service2 ~> service3 chainedServices({ result, _ in guard let result = result else { return } print(result) // ! Result: 42 })
  • 28. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 29. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 30. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 31. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 32. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 33. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 34. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 35. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 36. func ~> <T, U>(_ first: @escaping (CompletionHandler<T>) -> Void, _ transform: @escaping (T) -> U) -> (CompletionHandler<U>) -> Void { return { completion in first({ result, error in guard let result = result else { completion(nil, error); return } completion(transform(result), nil) }) } }
  • 37. let chainedWithMap = service1 ~> { int in return String(int / 2) } ~> service3 chainedWithMap({ result, _ in guard let result = result else { return } print(result) // Prints: 21 })
  • 38. let chainedWithMap = service1 ~> { int in return String(int / 2) } ~> service3 chainedWithMap({ result, _ in guard let result = result else { return } print(result) // Prints: 21 })
  • 39. !
  • 40. !