SlideShare a Scribd company logo
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Advanced functional
programming
Pragmatic use cases for Monads
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Functional Programming
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
First-class and higher-order functions
let double: (Int) -> Int = { $0 * 2 }
func apply(value: Int, function: (Int) -> Int) -> Int {
return function(value)
}
let result = apply(value: 4, function: double)
// result == 8
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Some properties
• A function is said to be pure if it produces no side-effects and its
return value only depends on its arguments
• An expression is said to be referentially transparent if it can be
replaced by its value without altering the program’s behavior
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Optionals
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Some very familiar code
var data: [String]?
// ...
let result = data?.first?.uppercased()
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Some very familiar code
var data: [String]?
// ...
let result = data?.first?.uppercased()
The operator ?. allows us to declare a workflow that will be executed
in order, and will prematurely stop if a nil value is encountered
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Let’s try to write the code for ?.
extension Optional {
func ?.<U>(lhs: Wrapped?, rhs: (Wrapped) -> U) -> U? {
switch self {
case .some(let value):
return .some(rhs(value))
case .none:
return nil
}
}
}
Disclaimer : this is a simplified
case for methods with no
arguments
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Arrays
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Let’s manipulate an Array
let data: [Int] = [0, 1, 2]
let result = data.map { $0 * 2 }.map { $0 * $0 }
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Let’s manipulate an Array
let data: [Int] = [0, 1, 2]
let result = data.map { $0 * 2 }.map { $0 * $0 }
Same thing here: the function map allows us to declare a workflow
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
A possible implementation for map
extension Array {
func map<U>(_ transform: (Element) -> U) -> [U] {
var result: [U] = []
for e in self {
result.append(transform(e))
}
return result
}
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Functions
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Let’s compose functions
let double: (Int) -> Int = { x in x * 2 }
let square: (Int) -> Int = { x in x * x }
infix operator • : AdditionPrecedence
func •<T, U, V>(lhs: (U) -> V, rhs: (T) -> U) -> ((T) -> V) {
return { t in lhs(rhs(t)) }
}
let result = (double • square)(4) // result == 32
Disclaimer : @escaping
attributes have been omitted
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Let’s compose functions
let double: (Int) -> Int = { x in x * 2 }
let square: (Int) -> Int = { x in x * x }
infix operator • : AdditionPrecedence
func •<T, U, V>(lhs: (U) -> V, rhs: (T) -> U) -> ((T) -> V) {
return { t in lhs(rhs(t)) }
}
let result = (double • square)(4) // result == 32
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
We have three similar behaviors,
yet backed by very different
implementation
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
What are the common parts?
• They contain value(s) inside a context
• They add new features to existing types
• They provide an interface to transform/map the inner value
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Monad: intuitive definition
• Wraps a type inside a context
• Provides a mechanism to create a workflow of transforms
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Minimal Monad
struct Monad<T> {
let value: T
// additional data
static func just(_ value: T) -> Monad<T> {
return self.init(value: value)
}
}
infix operator >>> : AdditionPrecedence
func >>> <U, V>(lhs: Monad<U>, rhs: (U) -> Monad<V>) -> Monad<V> {
// specific combination code
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Let’s look at an application
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Writer Monad
• We have an application that does a lot of numerical calculation
• It’s hard to keep track of how values have been computed
• We would like to have a way to store a value along with a log of all
the transformation it went through
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Writer Monad
struct Logged<T> {
let value: T
let logs: [String]
private init(value: T) {
self.value = value
self.logs = ["initialized with value: (self.value)"]
}
static func just(_ value: T) -> Logged<T> {
return Logged(value: value)
}
}
func >>> <U, V>(lhs: Logged<U>, rhs: (U) -> Logged<V>) -> Logged<V> {
let computation = rhs(lhs.value)
return Logged<V>(value: computation.value, logs: lhs.logs + computation.logs)
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Writer Monad
func square(_ value: Int) -> Logged<Int> {
let result = value * value
return Logged(value: result, log: "(value) was squared, result: (result)")
}
func halve(_ value: Int) -> Logged<Int> {
let result = value / 2
return Logged(value: result, log: "(value) was halved, result: (result)")
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Writer Monad
let computation = .just(4) >>> square >>> halve
print(computation)
// Logged<Int>(value: 8, logs: ["initialized with value: 4",
"4 was squared, result: 16", "16 was halved, result: 8"])
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Now let’s think architecture
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Now let’s think architecture
We can model the current state of an app with a struct
struct AppState {
let userName: String
let currentSong: URL?
let favoriteSongs: [URL]
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Now let’s think architecture
We can model the action our app emits, in a declarative fashion
protocol Action { }
struct UpdateUserNameAction: Action {
let newUserName: String
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Now let’s think architecture
We can react to those actions in a functional way
infix operator >>> : AdditionPrecedence
func >>>(appstate: AppState?, action: Action) -> AppState {
var appstate = appstate ?? AppState()
switch action {
case let newUserNameAction as UpdateUserNameAction:
appstate.userName = newUserNameAction.newUserName
default:
break
}
return appstate
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Now let’s think architecture
And finally we put everything together
AppState() >>> UpdateUserNameAction(newUserName: "Vincent")
// AppState(userName: Optional("Vincent"), currentSong: nil,
favoriteSongs: [])
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
ReSwift
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
ReSwift
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Minimal example
import ReSwift
struct AppState: StateType {
// ... app state properties here ...
}
func appReducer(action: Action, state: AppState?) -> AppState {
// ...
}
let store = Store(
reducer: appReducer,
state: AppState(), // You may also start with `nil`
middleware: []) // Middlewares are optional
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
A more « real life » example
func appReducer(action: Action, state: AppState?) -> AppState {
return AppState(
navigationState: navigationReducer(state?.navigationState, action: action),
authenticationState: authenticationReducer(state?.authenticationState, action: action),
repositories: repositoriesReducer(state?.repositories, action: action),
bookmarks: bookmarksReducer(state?.bookmarks, action: action)
)
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
A more « real life » example
func authenticationReducer(state: AuthenticationState?, action: Action) -> AuthenticationState {
var state = state ?? initialAuthenticationState()
switch action {
case _ as ReSwiftInit:
break
case let action as SetOAuthURL:
state.oAuthURL = action.oAuthUrl
case let action as UpdateLoggedInState:
state.loggedInState = action.loggedInState
default:
break
}
return state
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
A more « real life » example
let store: Store<AppState> = Store(reducer: appReducer, state: nil) // in AppDelegate file
class BookmarksViewController: UIViewController, StoreSubscriber {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
store.subscribe(self) { subcription in
return subcription.select { state in return state.bookmarks }
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
store.unsubscribe(self)
}
func newState(state: StateType?) {
// update view
}
}
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Advantages
• Reducers are pure (stateless) functions, easy to test
• Code review of business logic is easier
• A « demo » mode of the app is easy to implement (UI Testing)
• Deep-linking becomes a trivial use-case
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Drawbacks
• Not a silver bullet, a bit overkill for web-service driven apps
• Requires to create a lot of types (but at least not ObjC types)
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Questions ?
Vincent Pradeilles - CocoaHeads Lyon - 21/09/17
Bibliography
• https://en.wikipedia.org/wiki/Monad_(functional_programming)
• https://www.youtube.com/watch?v=ZhuHCtR3xq8 (Brian Beckman: Don't fear
the Monad)
• https://academy.realm.io/posts/slug-raheel-ahmad-using-monads-functional-
paradigms-in-practice-functors-patterns-swift/ (Using Monads and Other
Functional Paradigms in Practice)
• https://github.com/orakaro/Swift-monad-Maybe-Reader-and-Try
• https://academy.realm.io/posts/benji-encz-unidirectional-data-flow-swift/
(Unidirectional Data Flow: Shrinking Massive View Controllers)

More Related Content

PDF
Monads in Swift
PDF
Cocoa heads 09112017
PDF
IoT Best practices
PDF
Présentation de HomeKit
PPTX
Mca 2nd sem u-4 operator overloading
PDF
Découvrir dtrace en ligne de commande.
PDF
Protocol-Oriented Programming in Swift
PDF
Protocol in Swift
Monads in Swift
Cocoa heads 09112017
IoT Best practices
Présentation de HomeKit
Mca 2nd sem u-4 operator overloading
Découvrir dtrace en ligne de commande.
Protocol-Oriented Programming in Swift
Protocol in Swift

What's hot (20)

PDF
Map kit light
PPTX
#OOP_D_ITS - 5th - C++ Oop Operator Overloading
PPTX
Operator Overloading & Type Conversions
PDF
Swift で JavaScript 始めませんか? #iOSDC
PDF
Introduction to reactive programming & ReactiveCocoa
PDF
Swift Sequences & Collections
PPTX
operator overloading
PPTX
Bca 2nd sem u-4 operator overloading
PDF
JavaScript Core
PPTX
Operator overloading
PDF
JavaScript Functions
ODP
From object oriented to functional domain modeling
PDF
ReactiveCocoa in Practice
PDF
JavaScript in 2016
PPTX
Thinking Functionally with JavaScript
PDF
EcmaScript 6 - The future is here
PDF
Callbacks and control flow in Node js
PDF
An Introduction to Reactive Cocoa
PDF
Js interpreter interpreted
PDF
ReactiveCocoa Goodness - Part I of II
Map kit light
#OOP_D_ITS - 5th - C++ Oop Operator Overloading
Operator Overloading & Type Conversions
Swift で JavaScript 始めませんか? #iOSDC
Introduction to reactive programming & ReactiveCocoa
Swift Sequences & Collections
operator overloading
Bca 2nd sem u-4 operator overloading
JavaScript Core
Operator overloading
JavaScript Functions
From object oriented to functional domain modeling
ReactiveCocoa in Practice
JavaScript in 2016
Thinking Functionally with JavaScript
EcmaScript 6 - The future is here
Callbacks and control flow in Node js
An Introduction to Reactive Cocoa
Js interpreter interpreted
ReactiveCocoa Goodness - Part I of II
Ad

Viewers also liked (11)

PDF
CONTINUOUS DELIVERY WITH FASTLANE
PDF
Quoi de neuf dans iOS 10.3
PPTX
iOS Coding Best Practices
PDF
Handle the error
PDF
Design like a developer
PDF
Make Acccessibility Great Again
PDF
Super combinators
PDF
Cocoaheads
PDF
L'intégration continue avec Bitrise
PDF
Tout savoir pour devenir Freelance
PPTX
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
CONTINUOUS DELIVERY WITH FASTLANE
Quoi de neuf dans iOS 10.3
iOS Coding Best Practices
Handle the error
Design like a developer
Make Acccessibility Great Again
Super combinators
Cocoaheads
L'intégration continue avec Bitrise
Tout savoir pour devenir Freelance
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
Ad

Similar to Advanced functional programing in Swift (20)

PDF
An introduction to functional programming with Swift
PDF
Introduction to Swift 2
PDF
Swift Rocks #2: Going functional
PDF
NSCoder Swift - An Introduction to Swift
PPTX
Swift as an OOP Language
PDF
Workshop Swift
PPTX
Functional GUIs with F#
PDF
What Swift can teach us all
PDF
Cocoa Design Patterns in Swift
PDF
FormsKit: reactive forms driven by state. UA Mobile 2017.
PDF
Tech fest
PDF
Writing clean code
PDF
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
PDF
Quick swift tour
PDF
Swift Programming Language
PDF
Pragmatic Swift
PDF
Swift - the future of iOS app development
PDF
Deep Dive Into Swift
PDF
iOSNeXT.ro - 10 reasons you'll love Swift - Paul Ardeleanu
PDF
Orthogonality: A Strategy for Reusable Code
An introduction to functional programming with Swift
Introduction to Swift 2
Swift Rocks #2: Going functional
NSCoder Swift - An Introduction to Swift
Swift as an OOP Language
Workshop Swift
Functional GUIs with F#
What Swift can teach us all
Cocoa Design Patterns in Swift
FormsKit: reactive forms driven by state. UA Mobile 2017.
Tech fest
Writing clean code
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Quick swift tour
Swift Programming Language
Pragmatic Swift
Swift - the future of iOS app development
Deep Dive Into Swift
iOSNeXT.ro - 10 reasons you'll love Swift - Paul Ardeleanu
Orthogonality: A Strategy for Reusable Code

More from Vincent Pradeilles (8)

PDF
On-Boarding New Engineers
PDF
The underestimated power of KeyPaths
PDF
Solving callback hell with good old function composition
PDF
Taking the boilerplate out of your tests with Sourcery
PDF
How to build a debug view almost for free
PDF
An introduction to property-based testing
PDF
Implementing pseudo-keywords through Functional Programing
PDF
Property Wrappers or how Swift decided to become Java
On-Boarding New Engineers
The underestimated power of KeyPaths
Solving callback hell with good old function composition
Taking the boilerplate out of your tests with Sourcery
How to build a debug view almost for free
An introduction to property-based testing
Implementing pseudo-keywords through Functional Programing
Property Wrappers or how Swift decided to become Java

Recently uploaded (20)

PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
ai tools demonstartion for schools and inter college
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPT
Introduction Database Management System for Course Database
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Nekopoi APK 2025 free lastest update
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Introduction to Artificial Intelligence
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
AI in Product Development-omnex systems
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
ai tools demonstartion for schools and inter college
Operating system designcfffgfgggggggvggggggggg
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Internet Downloader Manager (IDM) Crack 6.42 Build 41
How to Choose the Right IT Partner for Your Business in Malaysia
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Introduction Database Management System for Course Database
Navsoft: AI-Powered Business Solutions & Custom Software Development
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Which alternative to Crystal Reports is best for small or large businesses.pdf
Wondershare Filmora 15 Crack With Activation Key [2025
Nekopoi APK 2025 free lastest update
CHAPTER 2 - PM Management and IT Context
Introduction to Artificial Intelligence
Odoo Companies in India – Driving Business Transformation.pdf
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
AI in Product Development-omnex systems

Advanced functional programing in Swift

  • 1. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Advanced functional programming Pragmatic use cases for Monads
  • 2. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Functional Programming
  • 3. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 First-class and higher-order functions let double: (Int) -> Int = { $0 * 2 } func apply(value: Int, function: (Int) -> Int) -> Int { return function(value) } let result = apply(value: 4, function: double) // result == 8
  • 4. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Some properties • A function is said to be pure if it produces no side-effects and its return value only depends on its arguments • An expression is said to be referentially transparent if it can be replaced by its value without altering the program’s behavior
  • 5. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Optionals
  • 6. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Some very familiar code var data: [String]? // ... let result = data?.first?.uppercased()
  • 7. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Some very familiar code var data: [String]? // ... let result = data?.first?.uppercased() The operator ?. allows us to declare a workflow that will be executed in order, and will prematurely stop if a nil value is encountered
  • 8. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Let’s try to write the code for ?. extension Optional { func ?.<U>(lhs: Wrapped?, rhs: (Wrapped) -> U) -> U? { switch self { case .some(let value): return .some(rhs(value)) case .none: return nil } } } Disclaimer : this is a simplified case for methods with no arguments
  • 9. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Arrays
  • 10. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Let’s manipulate an Array let data: [Int] = [0, 1, 2] let result = data.map { $0 * 2 }.map { $0 * $0 }
  • 11. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Let’s manipulate an Array let data: [Int] = [0, 1, 2] let result = data.map { $0 * 2 }.map { $0 * $0 } Same thing here: the function map allows us to declare a workflow
  • 12. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 A possible implementation for map extension Array { func map<U>(_ transform: (Element) -> U) -> [U] { var result: [U] = [] for e in self { result.append(transform(e)) } return result } }
  • 13. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Functions
  • 14. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Let’s compose functions let double: (Int) -> Int = { x in x * 2 } let square: (Int) -> Int = { x in x * x } infix operator • : AdditionPrecedence func •<T, U, V>(lhs: (U) -> V, rhs: (T) -> U) -> ((T) -> V) { return { t in lhs(rhs(t)) } } let result = (double • square)(4) // result == 32 Disclaimer : @escaping attributes have been omitted
  • 15. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Let’s compose functions let double: (Int) -> Int = { x in x * 2 } let square: (Int) -> Int = { x in x * x } infix operator • : AdditionPrecedence func •<T, U, V>(lhs: (U) -> V, rhs: (T) -> U) -> ((T) -> V) { return { t in lhs(rhs(t)) } } let result = (double • square)(4) // result == 32
  • 16. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 We have three similar behaviors, yet backed by very different implementation
  • 17. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 What are the common parts? • They contain value(s) inside a context • They add new features to existing types • They provide an interface to transform/map the inner value
  • 18. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Monad: intuitive definition • Wraps a type inside a context • Provides a mechanism to create a workflow of transforms
  • 19. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Minimal Monad struct Monad<T> { let value: T // additional data static func just(_ value: T) -> Monad<T> { return self.init(value: value) } } infix operator >>> : AdditionPrecedence func >>> <U, V>(lhs: Monad<U>, rhs: (U) -> Monad<V>) -> Monad<V> { // specific combination code }
  • 20. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Let’s look at an application
  • 21. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Writer Monad • We have an application that does a lot of numerical calculation • It’s hard to keep track of how values have been computed • We would like to have a way to store a value along with a log of all the transformation it went through
  • 22. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Writer Monad struct Logged<T> { let value: T let logs: [String] private init(value: T) { self.value = value self.logs = ["initialized with value: (self.value)"] } static func just(_ value: T) -> Logged<T> { return Logged(value: value) } } func >>> <U, V>(lhs: Logged<U>, rhs: (U) -> Logged<V>) -> Logged<V> { let computation = rhs(lhs.value) return Logged<V>(value: computation.value, logs: lhs.logs + computation.logs) }
  • 23. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Writer Monad func square(_ value: Int) -> Logged<Int> { let result = value * value return Logged(value: result, log: "(value) was squared, result: (result)") } func halve(_ value: Int) -> Logged<Int> { let result = value / 2 return Logged(value: result, log: "(value) was halved, result: (result)") }
  • 24. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Writer Monad let computation = .just(4) >>> square >>> halve print(computation) // Logged<Int>(value: 8, logs: ["initialized with value: 4", "4 was squared, result: 16", "16 was halved, result: 8"])
  • 25. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Now let’s think architecture
  • 26. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Now let’s think architecture We can model the current state of an app with a struct struct AppState { let userName: String let currentSong: URL? let favoriteSongs: [URL] }
  • 27. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Now let’s think architecture We can model the action our app emits, in a declarative fashion protocol Action { } struct UpdateUserNameAction: Action { let newUserName: String }
  • 28. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Now let’s think architecture We can react to those actions in a functional way infix operator >>> : AdditionPrecedence func >>>(appstate: AppState?, action: Action) -> AppState { var appstate = appstate ?? AppState() switch action { case let newUserNameAction as UpdateUserNameAction: appstate.userName = newUserNameAction.newUserName default: break } return appstate }
  • 29. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Now let’s think architecture And finally we put everything together AppState() >>> UpdateUserNameAction(newUserName: "Vincent") // AppState(userName: Optional("Vincent"), currentSong: nil, favoriteSongs: [])
  • 30. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 ReSwift
  • 31. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 ReSwift
  • 32. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Minimal example import ReSwift struct AppState: StateType { // ... app state properties here ... } func appReducer(action: Action, state: AppState?) -> AppState { // ... } let store = Store( reducer: appReducer, state: AppState(), // You may also start with `nil` middleware: []) // Middlewares are optional
  • 33. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 A more « real life » example func appReducer(action: Action, state: AppState?) -> AppState { return AppState( navigationState: navigationReducer(state?.navigationState, action: action), authenticationState: authenticationReducer(state?.authenticationState, action: action), repositories: repositoriesReducer(state?.repositories, action: action), bookmarks: bookmarksReducer(state?.bookmarks, action: action) ) }
  • 34. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 A more « real life » example func authenticationReducer(state: AuthenticationState?, action: Action) -> AuthenticationState { var state = state ?? initialAuthenticationState() switch action { case _ as ReSwiftInit: break case let action as SetOAuthURL: state.oAuthURL = action.oAuthUrl case let action as UpdateLoggedInState: state.loggedInState = action.loggedInState default: break } return state }
  • 35. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 A more « real life » example let store: Store<AppState> = Store(reducer: appReducer, state: nil) // in AppDelegate file class BookmarksViewController: UIViewController, StoreSubscriber { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) store.subscribe(self) { subcription in return subcription.select { state in return state.bookmarks } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) store.unsubscribe(self) } func newState(state: StateType?) { // update view } }
  • 36. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Advantages • Reducers are pure (stateless) functions, easy to test • Code review of business logic is easier • A « demo » mode of the app is easy to implement (UI Testing) • Deep-linking becomes a trivial use-case
  • 37. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Drawbacks • Not a silver bullet, a bit overkill for web-service driven apps • Requires to create a lot of types (but at least not ObjC types)
  • 38. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Questions ?
  • 39. Vincent Pradeilles - CocoaHeads Lyon - 21/09/17 Bibliography • https://en.wikipedia.org/wiki/Monad_(functional_programming) • https://www.youtube.com/watch?v=ZhuHCtR3xq8 (Brian Beckman: Don't fear the Monad) • https://academy.realm.io/posts/slug-raheel-ahmad-using-monads-functional- paradigms-in-practice-functors-patterns-swift/ (Using Monads and Other Functional Paradigms in Practice) • https://github.com/orakaro/Swift-monad-Maybe-Reader-and-Try • https://academy.realm.io/posts/benji-encz-unidirectional-data-flow-swift/ (Unidirectional Data Flow: Shrinking Massive View Controllers)