SlideShare a Scribd company logo
1 of 33
Download to read offline
Monads
Functional Programming
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
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
Optionals
Some very familiar code
var data: [String]?
// ...
let result = data?.first?.uppercased()
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
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
Arrays
Let’s manipulate an Array
let data: [Int] = [0, 1, 2]
let result = data.map { $0 * 2 }.map { $0 * $0 }
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
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
}
}
Functions
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
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
We have three similar behaviors,
yet backed by very different
implementation
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
Monad: intuitive definition
• Wraps a type inside a context
• Provides a mechanism to create a workflow of transforms
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
}
Some applications
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
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)
}
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)")
}
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"])
Reader Monad
• We have a function that require environment variables
• We don’t want to hard code those variables, because it makes
testing impossible
• We would like to have a way to declare the operation we want to
perform, but they would be actually executed only when we provide
the environment variables
Reader Monad
struct Reader<E, A> {
let g: (E) -> A
init(g: @escaping (E) -> A) {
self.g = g
}
func apply(_ e: E) -> A {
return g(e)
}
func flatMap<B>(_ f: @escaping (A) -> Reader<E, B>) -> Reader<E, B> {
return Reader<E, B> { e in f(self.g(e)).g(e) }
}
}
func >>> <E, A, B>(a: Reader<E, A>, f: @autoclosure @escaping (A) -> Reader<E, B>) ->
Reader<E, B> {
return a.flatMap(f)
}
Reader Monad
struct Environment {
var dbPath: String
}
func delete(_ userName: String) -> Reader<Environment, Void> {
return Reader<Environment, Void> { env in
print("Delete (userName) at DB path: (env.dbPath)")
}
}
let testWorkflow = delete("Thor") >>> delete("Loki")
let productionWorkflow = delete("Odin")
testWorkflow.apply(Environment(dbPath: "path_to_test"))
productionWorkflow.apply(Environment(dbPath: "path_to_prod"))
IO Monad
• We like pure functional programs because they have no side-effects
• Unfortunately, programs also need to do I/O, which bears side-
effects by definition
• The IO Monad allows us to encapsulate those side effects, and use
them in a pure functional way
IO Monad
enum IO<T> {
case value(T)
case error
static func just(_ value: T) -> IO<T> {
return .value(value)
}
}
func wrightLine<T>(_ value: T) -> IO<Void> {
print(value as Any)
return IO<Void>.just(())
}
func getLine(_: Void) -> IO<String> {
switch readLine() {
case let value?:
return .value(value)
case nil:
return .error
}
}
@discardableResult func >>> <U, V>(lhs: IO<U>, rhs: (U) -> IO<V>) -> IO<V> {
switch lhs {
case .error:
return .error
case .value(let lhs):
return rhs(lhs)
}
}
IO Monad
.just(()) >>> getLine
>>> { IO<String>.just($0.uppercased()) }
>>> wrightLine
> Hello world!
// HELLO WORLD!
Formal definition
struct Monad<T> {
let value: T
static func just(_ value: T) -> Monad<T>
}
func >>> <U, V>(lhs: Monad<U>, rhs: (U) -> Monad<V>) ->
Monad<V>
The following API:
Is a Monad if
let x: T, (.just(x) >>> f) == f(x)
let m: (U) -> Monad(V), (m >>> just) == m
let f, g, h: (T) -> T, f >>> g >>> h == f >>> { x in f(x) >>> h(x)
Associativity
Neutral element
How about mobile apps?
Questions ?
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

More Related Content

What's hot (6)

Pandas Dataframe reading data Kirti final.pptx
Pandas Dataframe reading data  Kirti final.pptxPandas Dataframe reading data  Kirti final.pptx
Pandas Dataframe reading data Kirti final.pptx
 
説明会資料
説明会資料 説明会資料
説明会資料
 
1010교재 협동조합의 이해
1010교재 협동조합의 이해1010교재 협동조합의 이해
1010교재 협동조합의 이해
 
エクセルで学ぶビジネス・シミュレーション①: 超入門
エクセルで学ぶビジネス・シミュレーション①: 超入門エクセルで学ぶビジネス・シミュレーション①: 超入門
エクセルで学ぶビジネス・シミュレーション①: 超入門
 
Data Analysis packages
Data Analysis packagesData Analysis packages
Data Analysis packages
 
Python - An Introduction
Python - An IntroductionPython - An Introduction
Python - An Introduction
 

Viewers also liked

Viewers also liked (12)

Cocoa heads 09112017
Cocoa heads 09112017Cocoa heads 09112017
Cocoa heads 09112017
 
Cocoaheads
CocoaheadsCocoaheads
Cocoaheads
 
Design like a developer
Design like a developerDesign like a developer
Design like a developer
 
Handle the error
Handle the errorHandle the error
Handle the error
 
Tout savoir pour devenir Freelance
Tout savoir pour devenir FreelanceTout savoir pour devenir Freelance
Tout savoir pour devenir Freelance
 
Super combinators
Super combinatorsSuper combinators
Super combinators
 
L'intégration continue avec Bitrise
L'intégration continue avec BitriseL'intégration continue avec Bitrise
L'intégration continue avec Bitrise
 
Make Acccessibility Great Again
Make Acccessibility Great AgainMake Acccessibility Great Again
Make Acccessibility Great Again
 
Advanced functional programing in Swift
Advanced functional programing in SwiftAdvanced functional programing in Swift
Advanced functional programing in Swift
 
CONTINUOUS DELIVERY WITH FASTLANE
CONTINUOUS DELIVERY WITH FASTLANECONTINUOUS DELIVERY WITH FASTLANE
CONTINUOUS DELIVERY WITH FASTLANE
 
Quoi de neuf dans iOS 10.3
Quoi de neuf dans iOS 10.3Quoi de neuf dans iOS 10.3
Quoi de neuf dans iOS 10.3
 
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
AI and Machine Learning Demystified by Carol Smith at Midwest UX 2017
 

Similar to Monads in Swift

TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
Eelco Visser
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional Programming
Adam Getchell
 
How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1
Taisuke Oe
 

Similar to Monads in Swift (20)

New Functional Features of Java 8
New Functional Features of Java 8New Functional Features of Java 8
New Functional Features of Java 8
 
Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
C# programming
C# programming C# programming
C# programming
 
Functional Programming in Swift
Functional Programming in SwiftFunctional Programming in Swift
Functional Programming in Swift
 
Why Haskell Matters
Why Haskell MattersWhy Haskell Matters
Why Haskell Matters
 
Functions in advanced programming
Functions in advanced programmingFunctions in advanced programming
Functions in advanced programming
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
 
Introduction to kotlin + spring boot demo
Introduction to kotlin + spring boot demoIntroduction to kotlin + spring boot demo
Introduction to kotlin + spring boot demo
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional Programming
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
 
Array Cont
Array ContArray Cont
Array Cont
 
SeneJug java_8_prez_122015
SeneJug java_8_prez_122015SeneJug java_8_prez_122015
SeneJug java_8_prez_122015
 
How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1
 
functions
functionsfunctions
functions
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative Functors
 
Functional Programming
Functional ProgrammingFunctional Programming
Functional Programming
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
02 functions, variables, basic input and output of c++
02   functions, variables, basic input and output of c++02   functions, variables, basic input and output of c++
02 functions, variables, basic input and output of c++
 
Gdg almaty. Функциональное программирование в Java 8
Gdg almaty. Функциональное программирование в Java 8Gdg almaty. Функциональное программирование в Java 8
Gdg almaty. Функциональное программирование в Java 8
 

More from Vincent Pradeilles

An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
Vincent Pradeilles
 

More from Vincent Pradeilles (8)

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

Recently uploaded

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 

Recently uploaded (20)

WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!
WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!
WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and ApplicationsWSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...
WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...
WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...
 
WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...
WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...
WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...
 
Driving Innovation: Scania's API Revolution with WSO2
Driving Innovation: Scania's API Revolution with WSO2Driving Innovation: Scania's API Revolution with WSO2
Driving Innovation: Scania's API Revolution with WSO2
 
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public AdministrationWSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
WSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid EnvironmentsWSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid Environments
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next IntegrationWSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
 

Monads in Swift

  • 3. 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. 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
  • 6. Some very familiar code var data: [String]? // ... let result = data?.first?.uppercased()
  • 7. 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. 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
  • 10. Let’s manipulate an Array let data: [Int] = [0, 1, 2] let result = data.map { $0 * 2 }.map { $0 * $0 }
  • 11. 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. 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 } }
  • 14. 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. 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. We have three similar behaviors, yet backed by very different implementation
  • 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. Monad: intuitive definition • Wraps a type inside a context • Provides a mechanism to create a workflow of transforms
  • 19. 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 }
  • 21. 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. 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) } 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)") }
  • 23. 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"])
  • 24. Reader Monad • We have a function that require environment variables • We don’t want to hard code those variables, because it makes testing impossible • We would like to have a way to declare the operation we want to perform, but they would be actually executed only when we provide the environment variables
  • 25. Reader Monad struct Reader<E, A> { let g: (E) -> A init(g: @escaping (E) -> A) { self.g = g } func apply(_ e: E) -> A { return g(e) } func flatMap<B>(_ f: @escaping (A) -> Reader<E, B>) -> Reader<E, B> { return Reader<E, B> { e in f(self.g(e)).g(e) } } } func >>> <E, A, B>(a: Reader<E, A>, f: @autoclosure @escaping (A) -> Reader<E, B>) -> Reader<E, B> { return a.flatMap(f) }
  • 26. Reader Monad struct Environment { var dbPath: String } func delete(_ userName: String) -> Reader<Environment, Void> { return Reader<Environment, Void> { env in print("Delete (userName) at DB path: (env.dbPath)") } } let testWorkflow = delete("Thor") >>> delete("Loki") let productionWorkflow = delete("Odin") testWorkflow.apply(Environment(dbPath: "path_to_test")) productionWorkflow.apply(Environment(dbPath: "path_to_prod"))
  • 27. IO Monad • We like pure functional programs because they have no side-effects • Unfortunately, programs also need to do I/O, which bears side- effects by definition • The IO Monad allows us to encapsulate those side effects, and use them in a pure functional way
  • 28. IO Monad enum IO<T> { case value(T) case error static func just(_ value: T) -> IO<T> { return .value(value) } } func wrightLine<T>(_ value: T) -> IO<Void> { print(value as Any) return IO<Void>.just(()) } func getLine(_: Void) -> IO<String> { switch readLine() { case let value?: return .value(value) case nil: return .error } } @discardableResult func >>> <U, V>(lhs: IO<U>, rhs: (U) -> IO<V>) -> IO<V> { switch lhs { case .error: return .error case .value(let lhs): return rhs(lhs) } }
  • 29. IO Monad .just(()) >>> getLine >>> { IO<String>.just($0.uppercased()) } >>> wrightLine > Hello world! // HELLO WORLD!
  • 30. Formal definition struct Monad<T> { let value: T static func just(_ value: T) -> Monad<T> } func >>> <U, V>(lhs: Monad<U>, rhs: (U) -> Monad<V>) -> Monad<V> The following API: Is a Monad if let x: T, (.just(x) >>> f) == f(x) let m: (U) -> Monad(V), (m >>> just) == m let f, g, h: (T) -> T, f >>> g >>> h == f >>> { x in f(x) >>> h(x) Associativity Neutral element
  • 33. 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