7 Habits For a More Functional Swift
-
Upload
jason-larsen -
Category
Mobile
-
view
443 -
download
0
description
Transcript of 7 Habits For a More Functional Swift
![Page 1: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/1.jpg)
7 Habits For a More Functional Swift
![Page 2: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/2.jpg)
Jason Larsen
@jarsen
![Page 3: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/3.jpg)
7 Habits1. Avoid mutability
2. Avoid for-loops
3. Combine map/filter/reduce
4. Be lazy
5. Curry functions
6. Write DSLs
7. Stop objectifying code
![Page 4: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/4.jpg)
What is a Function?
f(x) = x * x
![Page 5: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/5.jpg)
Functions Are Mappings4 Do not mutate input
4 Do not change external state
4 Determined only by explicit inputs
![Page 6: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/6.jpg)
Consequences of Pure Functions4 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
![Page 7: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/7.jpg)
Consequences of Pure Functions4 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
![Page 8: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/8.jpg)
Is Swift Functional?
![Page 9: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/9.jpg)
#1
Let it be
![Page 10: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/10.jpg)
Bad// find the bug, and don't tell me you've never done thisfunc 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))}
![Page 11: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/11.jpg)
Goodfunc square(x: Int) -> Int { return x * x}
let a = [1,2,3,4,5]let b = a.map({x in square(x)})
![Page 12: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/12.jpg)
Beautifulfunc square(x: Int) -> Int { return x * x}
let a = [1,2,3,4,5]let b = a.map(square)
![Page 13: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/13.jpg)
Immutable structsstruct Person { let name: String let age: Int}
let alice = Person(name: "Alice", age: 22)let alice2 = Person(name: alice.name, age: 23) // transform data
![Page 14: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/14.jpg)
Transforming Immutable Objectsextension Dictionary { func dictionaryByUpdatingKey(key: Key, value: Value) -> Dictionary { var mutable = self mutable.updateValue(value, forKey: key) return mutable }}
let animalNoiseMap = ["cow" : "moo", "cat" : "meow"]let animalNoiseMapImproved = animalNoiseMap.dictionaryByUpdatingKey("dog", value: "woof")
![Page 15: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/15.jpg)
Transforming Immutable Objectsstruct 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)
![Page 16: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/16.jpg)
Transforming Immutable Objectsstruct 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)
![Page 17: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/17.jpg)
Transforming Immutable Objectsclass 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)
![Page 18: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/18.jpg)
#2
for the love of loops!
![Page 19: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/19.jpg)
MapMap each item in an existing collection to something else.
![Page 20: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/20.jpg)
FilterFind objects in a collection that match your criteria by filtering out everything that doesn't match.
![Page 21: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/21.jpg)
Uglyvar bestStudents = [Student]()
for student in students { if (student.grade > 90) { bestStudents.append(student) }}
![Page 22: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/22.jpg)
Beautifullet bestStudents = students.filter { $0.grade > 90 }
![Page 23: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/23.jpg)
Also Beautifulfunc isBestStudent(student: Student) -> Bool { return student.grade > 90}
let bestStudents = students.filter(isBestStudent)
![Page 24: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/24.jpg)
ReduceReduces all sequence elements into one value. Takes an initial value, passes that value through as an accumulator, which may be updated in each iteration.
![Page 25: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/25.jpg)
Uglylet a = [1,2,3,4,5]
var sum = 0for x in a { sum += x}
![Page 26: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/26.jpg)
Calculating Sums With Reducelet a = [1,2,3,4]let sum = a.reduce(0, combine: { (accumulator, value) in return accumulator + value})
![Page 27: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/27.jpg)
Calculating Sums With Reducelet a = [1,2,3,4]let sum = a.reduce(0, combine: { (accumulator, value) in accumulator + value })
![Page 28: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/28.jpg)
Calculating Sums With Reducelet a = [1,2,3,4]let sum = a.reduce(0, combine: { $0 + $1 })
![Page 29: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/29.jpg)
Calculating Sums With Reducelet a = [1,2,3,4]let sum = a.reduce(0, +)
![Page 30: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/30.jpg)
Finding the Max Value With Reducelet numbers = [1,4,15,23,9]
if let initial = numbers.first { let numMax = numbers.reduce(initial) { (m, x) in return x > m ? x : m }}
![Page 31: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/31.jpg)
Finding the Max Value With Reducelet numbers = [1,4,15,23,9]
if let initial = numbers.first { let numberMax = numbers.reduce(initial) { (m, x) in return max(m, x) }}
![Page 32: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/32.jpg)
Finding the Max Value With Reducelet numbers = [1,4,15,23,9]
if let initial = numbers.first { let numberMax = numbers.reduce(initial, max)}
![Page 33: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/33.jpg)
Counting Frequencies with Reducelet 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) }}
![Page 34: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/34.jpg)
Composing Filterstypealias Filter = CIImage -> CIImage
let filters: [Filter] = [colorOverlay, blur, drawTitle]let filteredImage = filters.reduce(image, combine: { $1($0) } )
![Page 35: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/35.jpg)
#3
By our powers combined
![Page 36: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/36.jpg)
struct Person { let name: String let age: UInt}
let people = [Person(name: "Alice", age: 22), Person(name: "Bob", age: 23), Person(name: "Mallory", age: 25)]let ageSum = people.map({$0.age}).reduce(0, combine: +)
![Page 37: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/37.jpg)
let people = [Person(name: "Alice", age: 22), Person(name: "Bob", age: 23), Person(name: "Mallory", age: 25)]let namesBeforeJason = people.map({$0.name}).filter { name in name.compare("Jason") == NSComparisonResult.OrderedAscending}
![Page 38: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/38.jpg)
Zip it uplet a = Array(1...5)let b = Array(6...10)let result = map(Zip2(a,b), +) // [7, 9, 11, 13, 15]
![Page 39: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/39.jpg)
#4
Be Lazy
![Page 40: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/40.jpg)
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 }}
![Page 41: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/41.jpg)
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 }}
![Page 42: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/42.jpg)
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())
![Page 43: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/43.jpg)
func filter<S : SequenceType>(source: S, includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element]
func map<S : SequenceType, T> (source: S, transform: (S.Generator.Element) -> T) -> [T]
![Page 44: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/44.jpg)
#5
Curried Functions. Yum.
![Page 45: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/45.jpg)
func addNormal(x:Int, y : Int) -> Int { return x + y}
let sum = addNormal(1, 2)
![Page 46: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/46.jpg)
func addCurried(x:Int) -> Int -> Int { return {y in return x + y}}
let sum = addCurried(1)(2)
![Page 47: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/47.jpg)
let numbers = Array(0...5)let numbersIncrementedBy1 = numbers.map(addCurried(1))let numbersIncrementedBy2 = numbers.map(addCurried(2))
![Page 48: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/48.jpg)
// 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)
![Page 49: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/49.jpg)
Instance Methods are Curriedclass 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.depositdepositor(account)(100) // balance is now 200
![Page 50: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/50.jpg)
#6
Domain-Specific Langauges
![Page 51: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/51.jpg)
Custom Flow Controlfunc unless(condition: Bool, then: () -> ()) { if (!condition) { then() }}
unless(1 != 1) { println("Phew. Identity holds.")}
![Page 52: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/52.jpg)
Cucumber-Style BDD Frameworkgiven("I have entered (.*) into the calculator") { n in let calculator = Calculator() calculator.push(n)}
![Page 53: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/53.jpg)
Sinatra-Style Web FrameworkGET("/greetings/:name") { request, params in let name = params["name"] ?? "Anonymous" let greeting = "<h1>Hello, \(name)!</h1>" return Response(body: greeting, code: 200)}
![Page 54: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/54.jpg)
Custom Operatorsinfix operator |> { associativity left }func |> (filter1: Filter, filter2: Filter) -> Filter { return {img in filter1(filter2(img))}}
let myFilter = blur(blurRadius) |> colorOverlay(overlayColor)let result = myFilter(image)
![Page 55: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/55.jpg)
#7
Stop Objectifying Code
![Page 56: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/56.jpg)
Objectification4 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
![Page 57: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/57.jpg)
Functionalization4 Data
4 Functions transform data
![Page 58: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/58.jpg)
Thinking About Data
![Page 59: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/59.jpg)
Arraysgreat 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
![Page 60: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/60.jpg)
Tuples / Named Tuplesfixed 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)
![Page 61: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/61.jpg)
DictionariesDictionaries are maps.
4 anything that needs to be mapped to something else
4 a JSON response
![Page 62: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/62.jpg)
StructsEncapsulate 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
![Page 63: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/63.jpg)
EnumsAnytime something has a set of options
4 HTTP Methods
4 Errors
4 Optionals
![Page 64: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/64.jpg)
ClassesObjects. Object Oriented Programming. Not a bad thing, but not terribly functional.
![Page 65: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/65.jpg)
Typealias All The Thingstypealias Filter = Request->Requesttypealias Handler = (Request,Parameters)->Responsetypealias Model = [String : [String]]typealias Renderer = Model -> Stringtypealias Parameters = [String: String]
![Page 66: 7 Habits For a More Functional Swift](https://reader034.fdocuments.in/reader034/viewer/2022051323/547e6dd8b47959c0508b4b59/html5/thumbnails/66.jpg)
Resources4 http://www.drewag.me/posts/practical-use-for-curried-functions-in-swift
4 https://www.skillsmatter.com/skillscasts/5678-an-introduction-to-haskell
4 http://matt.might.net/articles/implementing-laziness
4 http://www.scottlogic.com/blog/2014/06/26/swift-sequences.html
4 http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/