SlideShare a Scribd company logo
1 of 66
Download to read offline
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 DSLs 
7. Stop objectifying code
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 (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
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
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,2,3,4,5] 
var b = [Int]() 
for x in a { 
a.append(square(x)) 
}
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 alice2 = Person(name: alice.name, age: 23) // transform data
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")
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)
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)
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)
#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.filter(isBestStudent)
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.
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 accumulator + value 
})
Calculating Sums With Reduce 
let a = [1,2,3,4] 
let sum = a.reduce(0, combine: { (accumulator, value) in accumulator + value })
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.reduce(initial) { (m, x) in 
return x > m ? x : m 
} 
}
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) 
} 
}
Finding the Max Value With Reduce 
let numbers = [1,4,15,23,9] 
if let initial = numbers.first { 
let numberMax = numbers.reduce(initial, max) 
}
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) 
} 
}
Composing Filters 
typealias Filter = CIImage -> CIImage 
let filters: [Filter] = [colorOverlay, blur, drawTitle] 
let filteredImage = filters.reduce(image, combine: { $1($0) } )
#3 
By our powers combined
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: +)
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 
}
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() -> EvenNaturalNumbersGenerator { 
return EvenNaturalNumbersGenerator() 
} 
} 
class EvenNaturalNumbersGenerator : GeneratorType { 
var current = 2 
typealias Element = Int 
func next() -> Int? { 
let ret = current 
current += 2 
return ret 
} 
}
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 
} 
}
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())
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]
#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.map(addCurried(2))
// 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)
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
#6 
Domain-Specific Langauges
Custom Flow Control 
func unless(condition: Bool, then: () -> ()) { 
if (!condition) { 
then() 
} 
} 
unless(1 != 1) { 
println("Phew. Identity holds.") 
}
Cucumber-Style BDD Framework 
given("I have entered (.*) into the calculator") { n in 
let calculator = Calculator() 
calculator.push(n) 
}
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) 
}
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)
#7 
Stop Objectifying Code
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
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 results in a JSON response
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)
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 Anything you might use a tuple for 
4 Data related to a student - grade, first name, last 
name
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 
typealias Model = [String : [String]] 
typealias Renderer = Model -> String 
typealias Parameters = [String: String]
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

More Related Content

What's hot

Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Poor Man's Functional Programming
Poor Man's Functional ProgrammingPoor Man's Functional Programming
Poor Man's Functional ProgrammingDmitry Buzdin
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей КоваленкоFwdays
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)stasimus
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Python programming Part -6
Python programming Part -6Python programming Part -6
Python programming Part -6Megha V
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final TaglessJohn De Goes
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance HaskellJohan Tibell
 
Introduction to haskell
Introduction to haskellIntroduction to haskell
Introduction to haskellLuca Molteni
 
The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181Mahmoud Samir Fayed
 
Humble introduction to category theory in haskell
Humble introduction to category theory in haskellHumble introduction to category theory in haskell
Humble introduction to category theory in haskellJongsoo Lee
 
Why Haskell Matters
Why Haskell MattersWhy Haskell Matters
Why Haskell Mattersromanandreg
 
Functional programming with haskell
Functional programming with haskellFunctional programming with haskell
Functional programming with haskellfaradjpour
 
The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPathsVincent Pradeilles
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeLuka Jacobowitz
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheetDr. Volkan OBAN
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoidsLuka Jacobowitz
 
Traversals for all ocasions
Traversals for all ocasionsTraversals for all ocasions
Traversals for all ocasionsLuka Jacobowitz
 

What's hot (20)

Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Poor Man's Functional Programming
Poor Man's Functional ProgrammingPoor Man's Functional Programming
Poor Man's Functional Programming
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Python programming Part -6
Python programming Part -6Python programming Part -6
Python programming Part -6
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance Haskell
 
Introduction to haskell
Introduction to haskellIntroduction to haskell
Introduction to haskell
 
The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181The Ring programming language version 1.5.2 book - Part 33 of 181
The Ring programming language version 1.5.2 book - Part 33 of 181
 
Humble introduction to category theory in haskell
Humble introduction to category theory in haskellHumble introduction to category theory in haskell
Humble introduction to category theory in haskell
 
Scala collections
Scala collectionsScala collections
Scala collections
 
Why Haskell Matters
Why Haskell MattersWhy Haskell Matters
Why Haskell Matters
 
Functional programming with haskell
Functional programming with haskellFunctional programming with haskell
Functional programming with haskell
 
The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPaths
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to Free
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheet
 
Python Cheat Sheet
Python Cheat SheetPython Cheat Sheet
Python Cheat Sheet
 
Monoids, monoids, monoids
Monoids, monoids, monoidsMonoids, monoids, monoids
Monoids, monoids, monoids
 
Traversals for all ocasions
Traversals for all ocasionsTraversals for all ocasions
Traversals for all ocasions
 

Similar to 7 Habits For a More Functional Swift

Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
関数潮流(Function Tendency)
関数潮流(Function Tendency)関数潮流(Function Tendency)
関数潮流(Function Tendency)riue
 
Power of functions in a typed world
Power of functions in a typed worldPower of functions in a typed world
Power of functions in a typed worldDebasish Ghosh
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
Functional programming basics
Functional programming basicsFunctional programming basics
Functional programming basicsopenbala
 
Let’s Talk About Ruby
Let’s Talk About RubyLet’s Talk About Ruby
Let’s Talk About RubyIan Bishop
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Underscore.js
Underscore.jsUnderscore.js
Underscore.jstimourian
 
Rethink programming: a functional approach
Rethink programming: a functional approachRethink programming: a functional approach
Rethink programming: a functional approachFrancesco Bruni
 
Monadologie
MonadologieMonadologie
Monadologieleague
 
Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Jesper Kamstrup Linnet
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftMichele Titolo
 

Similar to 7 Habits For a More Functional Swift (20)

Elm: give it a try
Elm: give it a tryElm: give it a try
Elm: give it a try
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
関数潮流(Function Tendency)
関数潮流(Function Tendency)関数潮流(Function Tendency)
関数潮流(Function Tendency)
 
Power of functions in a typed world
Power of functions in a typed worldPower of functions in a typed world
Power of functions in a typed world
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Python : Functions
Python : FunctionsPython : Functions
Python : Functions
 
Begin with Python
Begin with PythonBegin with Python
Begin with Python
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Functional programming basics
Functional programming basicsFunctional programming basics
Functional programming basics
 
Let’s Talk About Ruby
Let’s Talk About RubyLet’s Talk About Ruby
Let’s Talk About Ruby
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
Underscore.js
Underscore.jsUnderscore.js
Underscore.js
 
A bit about Scala
A bit about ScalaA bit about Scala
A bit about Scala
 
Rethink programming: a functional approach
Rethink programming: a functional approachRethink programming: a functional approach
Rethink programming: a functional approach
 
Monadologie
MonadologieMonadologie
Monadologie
 
Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in Swift
 

More from Jason Larsen

Unidirectional Data Flow with Reactor
Unidirectional Data Flow with ReactorUnidirectional Data Flow with Reactor
Unidirectional Data Flow with ReactorJason Larsen
 
Unidirectional Data Flow in Swift
Unidirectional Data Flow in SwiftUnidirectional Data Flow in Swift
Unidirectional Data Flow in SwiftJason Larsen
 
Protocol Oriented JSON Parsing in Swift
Protocol Oriented JSON Parsing in SwiftProtocol Oriented JSON Parsing in Swift
Protocol Oriented JSON Parsing in SwiftJason Larsen
 
Data Pipelines in Swift
Data Pipelines in SwiftData Pipelines in Swift
Data Pipelines in SwiftJason Larsen
 
Simulated Annealing
Simulated AnnealingSimulated Annealing
Simulated AnnealingJason Larsen
 
Learn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great GoodLearn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great GoodJason Larsen
 

More from Jason Larsen (6)

Unidirectional Data Flow with Reactor
Unidirectional Data Flow with ReactorUnidirectional Data Flow with Reactor
Unidirectional Data Flow with Reactor
 
Unidirectional Data Flow in Swift
Unidirectional Data Flow in SwiftUnidirectional Data Flow in Swift
Unidirectional Data Flow in Swift
 
Protocol Oriented JSON Parsing in Swift
Protocol Oriented JSON Parsing in SwiftProtocol Oriented JSON Parsing in Swift
Protocol Oriented JSON Parsing in Swift
 
Data Pipelines in Swift
Data Pipelines in SwiftData Pipelines in Swift
Data Pipelines in Swift
 
Simulated Annealing
Simulated AnnealingSimulated Annealing
Simulated Annealing
 
Learn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great GoodLearn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great Good
 

7 Habits For a More Functional Swift

  • 1. 7 Habits For a More Functional Swift
  • 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. What is a Function? f(x) = x * x
  • 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)})
  • 12. Beautiful func square(x: Int) -> Int { return x * x } let a = [1,2,3,4,5] let b = a.map(square)
  • 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. 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. 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)
  • 18. #2 for the love of loops!
  • 19. Map Map each item in an existing collection to something else.
  • 20. Filter Find objects in a collection that match your criteria by filtering out everything that doesn't match.
  • 21. Ugly var bestStudents = [Student]() for student in students { if (student.grade > 90) { bestStudents.append(student) } }
  • 22. Beautiful let bestStudents = students.filter { $0.grade > 90 }
  • 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 })
  • 29. Calculating Sums With Reduce let a = [1,2,3,4] let sum = a.reduce(0, +)
  • 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) } }
  • 34. Composing Filters typealias Filter = CIImage -> CIImage let filters: [Filter] = [colorOverlay, blur, drawTitle] let filteredImage = filters.reduce(image, combine: { $1($0) } )
  • 35. #3 By our powers combined
  • 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. 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. Zip it up let a = Array(1...5) let b = Array(6...10) let result = map(Zip2(a,b), +) // [7, 9, 11, 13, 15]
  • 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())
  • 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]
  • 45. func addNormal(x:Int, y : Int) -> Int { return x + y } let sum = addNormal(1, 2)
  • 46. func addCurried(x:Int) -> Int -> Int { return {y in return x + y} } let sum = addCurried(1)(2)
  • 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
  • 51. Custom Flow Control func unless(condition: Bool, then: () -> ()) { if (!condition) { then() } } unless(1 != 1) { println("Phew. Identity holds.") }
  • 52. Cucumber-Style BDD Framework given("I have entered (.*) into the calculator") { n in let calculator = Calculator() calculator.push(n) }
  • 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. 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)
  • 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. Functionalization 4 Data 4 Functions transform data
  • 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)
  • 61. Dictionaries Dictionaries are maps. 4 anything that needs to be mapped to something else 4 a JSON response
  • 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. Enums Anytime something has a set of options 4 HTTP Methods 4 Errors 4 Optionals
  • 64. Classes Objects. Object Oriented Programming. Not a bad thing, but not terribly functional.
  • 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. 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