This document provides 7 habits for writing more functional Swift code. It discusses avoiding mutability and for-loops in favor of map, filter and reduce functions. It also covers being lazy, currying functions, writing domain-specific languages, and thinking about code in terms of data and functions rather than objects.
5. Functions Are Mappings
4 Do not mutate input
4 Do not change external state
4 Determined only by explicit inputs
6. Consequences of Pure Functions
4 Return the same values every time for input
4 No Side Effects
4 Purity allows laziness (since the value will be the
same whenever its computed, we can compute it only
when we need it)
4 Concurrency is easy, b/c no shared state
7. Consequences of Pure Functions
4 No I/O (user input, printing, random values, etc)
4 No state
4 No variables (writing to variables is a side effect)
4 No Side Effects
10. Bad
// find the bug, and don't tell me you've never done this
func square(x: Int) -> Int {
return x * x
}
var a = [1,2,3,4,5]
var b = [Int]()
for x in a {
a.append(square(x))
}
11. Good
func square(x: Int) -> Int {
return x * x
}
let a = [1,2,3,4,5]
let b = a.map({x in square(x)})
13. Immutable structs
struct Person {
let name: String
let age: Int
}
let alice = Person(name: "Alice", age: 22)
let alice2 = Person(name: alice.name, age: 23) // transform data
15. Transforming Immutable Objects
struct Person {
let name: String
let age: Int
func age(age: Int) -> Person {
return Person(name: self.name, age: age)
}
}
let bob = Person(name: "Bob", age: 25)
let birthdayBob = bob.age(bob.age + 1)
16. Transforming Immutable Objects
struct Person {
let name: String
let age: Int
static func age(person: Person, age: Int) -> Person {
return Person(name: person.name, age: age)
}
}
let bob = Person(name: "Bob", age: 25)
let birthdayBob = Person.age(bob, age: bob.age + 1)
17. Transforming Immutable Objects
class Person {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
init(person: Person, name: String? = nil, age: Int? = nil) {
self.name = name ?? person.name
self.age = age ?? person.age
}
}
let bob = Person(name: "Bob", age: 25)
let birthdayBob = Person(person: bob, age: bob.age + 1)
23. Also Beautiful
func isBestStudent(student: Student) -> Bool {
return student.grade > 90
}
let bestStudents = students.filter(isBestStudent)
24. Reduce
Reduces all sequence elements into one value. Takes an
initial value, passes that value through as an
accumulator, which may be updated in each iteration.
25. Ugly
let a = [1,2,3,4,5]
var sum = 0
for x in a {
sum += x
}
26. Calculating Sums With Reduce
let a = [1,2,3,4]
let sum = a.reduce(0, combine: { (accumulator, value) in
return accumulator + value
})
27. Calculating Sums With Reduce
let a = [1,2,3,4]
let sum = a.reduce(0, combine: { (accumulator, value) in accumulator + value })
28. Calculating Sums With Reduce
let a = [1,2,3,4]
let sum = a.reduce(0, combine: { $0 + $1 })
30. Finding the Max Value With Reduce
let numbers = [1,4,15,23,9]
if let initial = numbers.first {
let numMax = numbers.reduce(initial) { (m, x) in
return x > m ? x : m
}
}
31. Finding the Max Value With Reduce
let numbers = [1,4,15,23,9]
if let initial = numbers.first {
let numberMax = numbers.reduce(initial) { (m, x) in
return max(m, x)
}
}
32. Finding the Max Value With Reduce
let numbers = [1,4,15,23,9]
if let initial = numbers.first {
let numberMax = numbers.reduce(initial, max)
}
33. Counting Frequencies with Reduce
let numbers = [1,4,15,23,1,1,9,9,23,9]
let histogram = numbers.reduce([Int: Int]()) { (acc, x) in
if let count = acc[x] {
return acc.dictionaryByUpdatingKey(x, value: count + 1)
}
else {
return acc.dictionaryByUpdatingKey(x, value: 1)
}
}
40. class EvenNaturalNumbers: SequenceType {
typealias GeneratorType = EvenNaturalNumbersGenerator
func generate() -> EvenNaturalNumbersGenerator {
return EvenNaturalNumbersGenerator()
}
}
class EvenNaturalNumbersGenerator : GeneratorType {
var current = 2
typealias Element = Int
func next() -> Int? {
let ret = current
current += 2
return ret
}
}
41. class Fibonacci : SequenceType {
typealias GeneratorType = FibonacciGenerator
func generate() -> FibonacciGenerator {
return FibonacciGenerator()
}
}
class FibonacciGenerator : GeneratorType {
var current = 0, nextValue = 1
typealias Element = Int
func next() -> Int? {
let ret = current
current = nextValue
nextValue = nextValue + ret
return ret
}
}
42. func take<T, S : SequenceType where S.Generator.Element == T>(n: Int, sequence: S) -> [T] {
var gen = sequence.generate()
var values = [T]()
for _ in (1...n) {
if let value = gen.next() {
values.append(value)
}
}
return values
}
take(5, [1,2,5,12,31,4,2])
take(10, EvenNaturalNumbers())
take(10, Fibonacci())
47. let numbers = Array(0...5)
let numbersIncrementedBy1 = numbers.map(addCurried(1))
let numbersIncrementedBy2 = numbers.map(addCurried(2))
48. // taken from the excellent WIP "Functional Programming in Swift"
// http://www.objc.io/books/
typealias Filter = CIImage -> CIImage
func blur(radius: Double) -> Filter {
return { image in
let parameters : Parameters = [kCIInputRadiusKey: radius, kCIInputImageKey: image]
let filter = CIFilter(name:"CIGaussianBlur", parameters:parameters)
return filter.outputImage
}
}
let blurredImage = blur(2.0)(image)
49. Instance Methods are Curried
class BankAccount {
var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
}
let account = BankAccount()
account.deposit(100) // balance is now 100
let depositor = BankAccount.deposit
depositor(account)(100) // balance is now 200
56. Objectification
4 Class - Noun
4 Properties - Nouns related to noun above
4 Instance Methods - Actions instance of Class can
perform
4 Class Methods - Actions related to Class in general
59. Arrays
great for variable length data of the same type
4 list of students in a class
4 lines in a document
4 search results in a JSON response
60. Tuples / Named Tuples
fixed length list. can hold mixed types, but probably best
to prefer same types
4 Points/Vectors
4 functions with multiple return values
typealias Vector2D = (x: Double, y: Double)
let foo = Vector2D(2, 4)
62. Structs
Encapsulate properties of multiple types. No
inheritance. Free constructor for all the immutable
properties.
4 Anything you might use a tuple for
4 Data related to a student - grade, first name, last
name