Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
7 Habits For a More Functional Swift
Jason Larsen 
@jarsen
7 Habits 
1. Avoid mutability 
2. Avoid for-loops 
3. Combine map/filter/reduce 
4. Be lazy 
5. Curry functions 
6. Write ...
What is a Function? 
f(x) = x * x
Functions Are Mappings 
4 Do not mutate input 
4 Do not change external state 
4 Determined only by explicit inputs
Consequences of Pure Functions 
4 Return the same values every time for input 
4 No Side Effects 
4 Purity allows laziness...
Consequences of Pure Functions 
4 No I/O (user input, printing, random values, etc) 
4 No state 
4 No variables (writing t...
Is Swift Functional?
#1 
Let it be
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,...
Good 
func square(x: Int) -> Int { 
return x * x 
} 
let a = [1,2,3,4,5] 
let b = a.map({x in square(x)})
Beautiful 
func square(x: Int) -> Int { 
return x * x 
} 
let a = [1,2,3,4,5] 
let b = a.map(square)
Immutable structs 
struct Person { 
let name: String 
let age: Int 
} 
let alice = Person(name: "Alice", age: 22) 
let ali...
Transforming Immutable Objects 
extension Dictionary { 
func dictionaryByUpdatingKey(key: Key, value: Value) -> Dictionary...
Transforming Immutable Objects 
struct Person { 
let name: String 
let age: Int 
func age(age: Int) -> Person { 
return Pe...
Transforming Immutable Objects 
struct Person { 
let name: String 
let age: Int 
static func age(person: Person, age: Int)...
Transforming Immutable Objects 
class Person { 
let name: String 
let age: Int 
init(name: String, age: Int) { 
self.name ...
#2 
for the love of loops!
Map 
Map each item in an existing collection to something 
else.
Filter 
Find objects in a collection that match your criteria by 
filtering out everything that doesn't match.
Ugly 
var bestStudents = [Student]() 
for student in students { 
if (student.grade > 90) { 
bestStudents.append(student) 
...
Beautiful 
let bestStudents = students.filter { $0.grade > 90 }
Also Beautiful 
func isBestStudent(student: Student) -> Bool { 
return student.grade > 90 
} 
let bestStudents = students....
Reduce 
Reduces all sequence elements into one value. Takes an 
initial value, passes that value through as an 
accumulato...
Ugly 
let a = [1,2,3,4,5] 
var sum = 0 
for x in a { 
sum += x 
}
Calculating Sums With Reduce 
let a = [1,2,3,4] 
let sum = a.reduce(0, combine: { (accumulator, value) in 
return accumula...
Calculating Sums With Reduce 
let a = [1,2,3,4] 
let sum = a.reduce(0, combine: { (accumulator, value) in accumulator + va...
Calculating Sums With Reduce 
let a = [1,2,3,4] 
let sum = a.reduce(0, combine: { $0 + $1 })
Calculating Sums With Reduce 
let a = [1,2,3,4] 
let sum = a.reduce(0, +)
Finding the Max Value With Reduce 
let numbers = [1,4,15,23,9] 
if let initial = numbers.first { 
let numMax = numbers.red...
Finding the Max Value With Reduce 
let numbers = [1,4,15,23,9] 
if let initial = numbers.first { 
let numberMax = numbers....
Finding the Max Value With Reduce 
let numbers = [1,4,15,23,9] 
if let initial = numbers.first { 
let numberMax = numbers....
Counting Frequencies with Reduce 
let numbers = [1,4,15,23,1,1,9,9,23,9] 
let histogram = numbers.reduce([Int: Int]()) { (...
Composing Filters 
typealias Filter = CIImage -> CIImage 
let filters: [Filter] = [colorOverlay, blur, drawTitle] 
let fil...
#3 
By our powers combined
struct Person { 
let name: String 
let age: UInt 
} 
let people = [Person(name: "Alice", age: 22), 
Person(name: "Bob", ag...
let people = [Person(name: "Alice", age: 22), 
Person(name: "Bob", age: 23), 
Person(name: "Mallory", age: 25)] 
let names...
Zip it up 
let a = Array(1...5) 
let b = Array(6...10) 
let result = map(Zip2(a,b), +) // [7, 9, 11, 13, 15]
#4 
Be Lazy
class EvenNaturalNumbers: SequenceType { 
typealias GeneratorType = EvenNaturalNumbersGenerator 
func generate() -> EvenNa...
class Fibonacci : SequenceType { 
typealias GeneratorType = FibonacciGenerator 
func generate() -> FibonacciGenerator { 
r...
func take<T, S : SequenceType where S.Generator.Element == T>(n: Int, sequence: S) -> [T] { 
var gen = sequence.generate()...
func filter<S : SequenceType> 
(source: S, includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element] 
func m...
#5 
Curried Functions. Yum.
func addNormal(x:Int, y : Int) -> Int { 
return x + y 
} 
let sum = addNormal(1, 2)
func addCurried(x:Int) -> Int -> Int { 
return {y in return x + y} 
} 
let sum = addCurried(1)(2)
let numbers = Array(0...5) 
let numbersIncrementedBy1 = numbers.map(addCurried(1)) 
let numbersIncrementedBy2 = numbers.ma...
// taken from the excellent WIP "Functional Programming in Swift" 
// http://www.objc.io/books/ 
typealias Filter = CIImag...
Instance Methods are Curried 
class BankAccount { 
var balance: Double = 0.0 
func deposit(amount: Double) { 
balance += a...
#6 
Domain-Specific Langauges
Custom Flow Control 
func unless(condition: Bool, then: () -> ()) { 
if (!condition) { 
then() 
} 
} 
unless(1 != 1) { 
pr...
Cucumber-Style BDD Framework 
given("I have entered (.*) into the calculator") { n in 
let calculator = Calculator() 
calc...
Sinatra-Style Web Framework 
GET("/greetings/:name") { request, params in 
let name = params["name"] ?? "Anonymous" 
let g...
Custom Operators 
infix operator |> { associativity left } 
func |> (filter1: Filter, filter2: Filter) -> Filter { 
return...
#7 
Stop Objectifying Code
Objectification 
4 Class - Noun 
4 Properties - Nouns related to noun above 
4 Instance Methods - Actions instance of Clas...
Functionalization 
4 Data 
4 Functions transform data
Thinking About Data
Arrays 
great for variable length data of the same type 
4 list of students in a class 
4 lines in a document 
4 search re...
Tuples / Named Tuples 
fixed length list. can hold mixed types, but probably best 
to prefer same types 
4 Points/Vectors ...
Dictionaries 
Dictionaries are maps. 
4 anything that needs to be mapped to something else 
4 a JSON response
Structs 
Encapsulate properties of multiple types. No 
inheritance. Free constructor for all the immutable 
properties. 
4...
Enums 
Anytime something has a set of options 
4 HTTP Methods 
4 Errors 
4 Optionals
Classes 
Objects. Object Oriented Programming. Not a bad thing, 
but not terribly functional.
Typealias All The Things 
typealias Filter = Request->Request 
typealias Handler = (Request,Parameters)->Response 
typeali...
Resources 
4 http://www.drewag.me/posts/practical-use-for-curried- 
functions-in-swift 
4 https://www.skillsmatter.com/ski...
Upcoming SlideShare
Loading in …5
×

7 Habits For a More Functional Swift

10,065 views

Published on

Functional programming tips in swift.

Published in: Mobile
  • Hey guys! Who wants to chat with me? More photos with me here 👉 http://www.bit.ly/katekoxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

7 Habits For a More Functional Swift

  1. 1. 7 Habits For a More Functional Swift
  2. 2. Jason Larsen @jarsen
  3. 3. 7 Habits 1. Avoid mutability 2. Avoid for-loops 3. Combine map/filter/reduce 4. Be lazy 5. Curry functions 6. Write DSLs 7. Stop objectifying code
  4. 4. What is a Function? f(x) = x * x
  5. 5. Functions Are Mappings 4 Do not mutate input 4 Do not change external state 4 Determined only by explicit inputs
  6. 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. 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
  8. 8. Is Swift Functional?
  9. 9. #1 Let it be
  10. 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. 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)})
  12. 12. Beautiful func square(x: Int) -> Int { return x * x } let a = [1,2,3,4,5] let b = a.map(square)
  13. 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
  14. 14. Transforming Immutable Objects extension 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")
  15. 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. 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. 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)
  18. 18. #2 for the love of loops!
  19. 19. Map Map each item in an existing collection to something else.
  20. 20. Filter Find objects in a collection that match your criteria by filtering out everything that doesn't match.
  21. 21. Ugly var bestStudents = [Student]() for student in students { if (student.grade > 90) { bestStudents.append(student) } }
  22. 22. Beautiful let bestStudents = students.filter { $0.grade > 90 }
  23. 23. Also Beautiful func isBestStudent(student: Student) -> Bool { return student.grade > 90 } let bestStudents = students.filter(isBestStudent)
  24. 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. 25. Ugly let a = [1,2,3,4,5] var sum = 0 for x in a { sum += x }
  26. 26. Calculating Sums With Reduce let a = [1,2,3,4] let sum = a.reduce(0, combine: { (accumulator, value) in return accumulator + value })
  27. 27. Calculating Sums With Reduce let a = [1,2,3,4] let sum = a.reduce(0, combine: { (accumulator, value) in accumulator + value })
  28. 28. Calculating Sums With Reduce let a = [1,2,3,4] let sum = a.reduce(0, combine: { $0 + $1 })
  29. 29. Calculating Sums With Reduce let a = [1,2,3,4] let sum = a.reduce(0, +)
  30. 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. 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. 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. 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) } }
  34. 34. Composing Filters typealias Filter = CIImage -> CIImage let filters: [Filter] = [colorOverlay, blur, drawTitle] let filteredImage = filters.reduce(image, combine: { $1($0) } )
  35. 35. #3 By our powers combined
  36. 36. 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: +)
  37. 37. 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 }
  38. 38. Zip it up let a = Array(1...5) let b = Array(6...10) let result = map(Zip2(a,b), +) // [7, 9, 11, 13, 15]
  39. 39. #4 Be Lazy
  40. 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. 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. 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())
  43. 43. 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]
  44. 44. #5 Curried Functions. Yum.
  45. 45. func addNormal(x:Int, y : Int) -> Int { return x + y } let sum = addNormal(1, 2)
  46. 46. func addCurried(x:Int) -> Int -> Int { return {y in return x + y} } let sum = addCurried(1)(2)
  47. 47. let numbers = Array(0...5) let numbersIncrementedBy1 = numbers.map(addCurried(1)) let numbersIncrementedBy2 = numbers.map(addCurried(2))
  48. 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. 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
  50. 50. #6 Domain-Specific Langauges
  51. 51. Custom Flow Control func unless(condition: Bool, then: () -> ()) { if (!condition) { then() } } unless(1 != 1) { println("Phew. Identity holds.") }
  52. 52. Cucumber-Style BDD Framework given("I have entered (.*) into the calculator") { n in let calculator = Calculator() calculator.push(n) }
  53. 53. Sinatra-Style Web Framework GET("/greetings/:name") { request, params in let name = params["name"] ?? "Anonymous" let greeting = "<h1>Hello, (name)!</h1>" return Response(body: greeting, code: 200) }
  54. 54. Custom Operators infix 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)
  55. 55. #7 Stop Objectifying Code
  56. 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
  57. 57. Functionalization 4 Data 4 Functions transform data
  58. 58. Thinking About Data
  59. 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. 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)
  61. 61. Dictionaries Dictionaries are maps. 4 anything that needs to be mapped to something else 4 a JSON response
  62. 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
  63. 63. Enums Anytime something has a set of options 4 HTTP Methods 4 Errors 4 Optionals
  64. 64. Classes Objects. Object Oriented Programming. Not a bad thing, but not terribly functional.
  65. 65. Typealias All The Things typealias Filter = Request->Request typealias Handler = (Request,Parameters)->Response typealias Model = [String : [String]] typealias Renderer = Model -> String typealias Parameters = [String: String]
  66. 66. Resources 4 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

×