A quick look at Swift functional programming
CocoaheadsSKG
Dimitri James Tsiflitzis
What is functional programming?
In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing state, and mutable data.
Functional programming is a style of programming that explicitly uses functions that will always return the same result when called with the same input.
or
Filtering
The imperative way
var evens = [Int]()
for i in 1...10 {
if i % 2 == 0 {
evens.append(i)
}
}
print(evens)
/*
[2, 4, 6, 8, 10]
*/
Functional filtering
In Swift, filter(_:) is a method on Collection types, such as Swift arrays.
It accepts another function as a parameter. This other function accepts as input a single value from the array, and returns a Bool.
Functional filtering
filter
true
true
Functional filtering
func isEven(number: Int) -> Bool {
return number % 2 == 0
}
evens = Array(1...10).filter(isEven)
print(evens)
/*
[2, 4, 6, 8, 10]
*/
Functional filtering
/* functions in swift are just named closures */
evens = Array(1...10).filter { (number) in number % 2 == 0 }
print(evens)
/*
[2, 4, 6, 8, 10]
*/
Functional filtering
/* shorthand */
evens = Array(1...10).filter { $0 % 2 == 0 }
print(evens)
/*
[2, 4, 6, 8, 10]
*/
Functional filtering
Tip: Use the shorthand in simple situations when it will make sense at first glance to a future reader.
For more complicated scenarios you can use named arguments. Compilers have no feelings but humans do.
Don't give up on imperative programming just yet
func arrayFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
var result = [T]()
for i in source {
if predicate(i) {
result.append(i)
}
}
return result
}
Mapping
Functional mapping
The Collection method map(_:) accepts a single function as a parameter, and in turn, it produces an array of the same length after being applied to each element of the collection.
The return type of the mapped function does not have to be the same type as the collection elements.
Use map to loop over a collection and apply the same operation to each element in the collection.
Functional mapping
map
black
yellow
violet
ciel
f(black)
f(yellow)
f(violet)
f(ciel)
map
Functional mapping
typealias Years = Int
struct Person {
let name : String
let age : Years
}
let persons = [
Person(name: "John", age: 40),
Person(name: "Paul", age: 74),
Person(name: "George", age: 58),
Person(name: "Ringo", age: 76),
]
let personNames = persons.map { $0.name }
print(personNames)
/*
["John", "Paul", "George", "Ringo"]
*/
Imperative mapping
let values = [2.0,4.0,5.0,7.0]
var squares: [Double] = []
for value in values {
squares.append(value*value)
}
print(squares)
/*
[4.0, 16.0, 25.0, 49.0]
*/
Functional mapping
let squares = [2.0,4.0,5.0,7.0]
func raiseSquare(number: Double) -> Double {
return number * number
}
squares = squares.map(raiseSquare)
print(squares)
/*
[4.0, 16.0, 25.0, 49.0]
*/
Functional mapping
let values = [2.0,4.0,5.0,7.0]
let squares = values.map({
(value: Double) -> Double in
return value * value
})
print(squares)
/*
[4.0, 16.0, 25.0, 49.0]
*/
Functional mapping
let values = [2.0,4.0,5.0,7.0]
let squares = values.map {value in value * value}
print(squares)
/*
[4.0, 16.0, 25.0, 49.0]
*/
Functional mapping
let values = [2.0,4.0,5.0,7.0]
let squares = values.map { $0 * $0 }
print(squares)
/*
[4.0, 16.0, 25.0, 49.0]
*/
Reducing
Functional reducing
The Collection method reduce(_:_:) takes two parameters. The first is a starting value of a generic type Element, and the second is a function that combines a value of type Element with an element in the collection to produce another value of type Element.
Use reduce to combine all items in a collection to create a single new value.
Functional reducing
black
yellow
violet
ciel
reduce
Functional reducing
let items = [2.0,4.0,5.0,7.0]
let total = items.reduce(10.0,+)
print(total)
/*
28.0
*/
Flat mapping
Flat mapping
Use it to flatten a collection of collections.
let collections = [[5,2,7],nil, [4,8], nil, [9,1,3]]
let flat = collections.flatMap { $0 }
/*
[5, 2, 7, 4, 8, 9, 1, 3]
*/
Bonus: Swift ignores optionals for you
Flat mapping
Powerful when you transform each subcollection
let collections = [[5,2,7],[4,8],[9,1,3]]
let onlyEven = collections.flatMap {
intArray in intArray.filter { $0 % 2 == 0 }
}
/*
[2, 4, 8]
*/
Chaining
Chaining
let marks = [4, 5, 8, 2, 9, 7]
let passingTotal = marks.filter{$0 >= 7}.reduce(0,combine: +)
/*
24
*/
let numbers = [20, 17, 35, 4, 12]
let evenSquares = numbers.map{$0 * $0}.filter{$0 % 2 == 0}
/*
[400, 16, 144]
*/
Thoughts
Swift is not a purely functional language but it allows you to be flexible and combine styles.
You can get started in your Model or ViewModel layer to get a feel for the lay of the land.
For your UI's checkout RxSwift. Reactive programming is an example of a functional programming, like, approach for UI development.
Your code will be easier to test when isolated into modular functions that are free from side effects. <~~ Famous Last Words
Ευχαριστούμε
A quick look at Swift functional programming
By tsif
A quick look at Swift functional programming
- 212