SlideShare a Scribd company logo
1 of 64
Download to read offline
Lenses and Prisms in Swift
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike
3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/
3.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
Functional getters and setters
Lenses and Prisms
→ encapsulate a relationship between a
data structure and its parts
→ simple to define
→ composition tools
→ build powerful abstractions
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
enum ViewState<T> {
case empty
case processing(String)
case failed(Error)
case completed(T)
}
enum ViewState<T> {
case empty
case processing(String)
case failed(Error)
case completed(T)
}
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
struct Lens<Whole,Part> {
let get: (Whole) -> Part
let set: (Part) -> (Whole) -> Whole
}
struct Prism<Whole,Part> {
let tryGet: (Whole) -> Part?
let inject: (Part) -> Whole
}
View
ViewModel
Functional
ViewModel
struct LoginPage {
var title: String
var credendials: CredentialBox
var buttonState: ViewState<Button>
}
struct CredentialBox {
var usernameField: TextField
var passwordField: TextField
}
struct TextField {
var text: String
var placeholder: String?
var secureText: Bool
}
struct Button {
var title: String
var enabled: Bool
}
struct LoginPage {
var title: String
var credendials: CredentialBox
var buttonState: ViewState<Button>
}
struct CredentialBox {
var usernameField: TextField
var passwordField: TextField
}
struct TextField {
var text: String
var placeholder: String?
var secureText: Bool
}
struct Button {
var title: String
var enabled: Bool
}
extension CredentialBox {
enum lens {
static var usernameField: Lens<CredentialBox,TextField> {
return Lens<CredentialBox,TextField>.init(
get: { whole in
whole.usernameField
},
set: { part in
{ whole in
var mutableWhole = whole
mutableWhole.usernameField = part
return mutableWhole
}
}
)
}
}
}
extension ViewState {
enum prism {
static var processing: Prism<ViewState,String> {
return .init(
tryGet: { whole in
guard case .processing(let message) = whole else {
return nil
}
return message
},
inject: { part in
.processing(part)
}
)
}
}
}
Manipulate the model
→ a previous model exists
→ set a greeting title
→ set a stored username
→ button initially not enabled
let initialState = (
title: "Welcome back!",
username: savedUsername,
buttonState: ViewState<Button>.completed(Button.init(
title: "Login",
enabled: false)))
var mutableNewModel = oldModel
mutableNewModel.title = initialState.title
mutableNewModel.credendials.usernameField.text = initialState.username
mutableNewModel.buttonState = initialState.buttonState
let initialState = (
title: "Welcome back!",
username: savedUsername,
buttonState: ViewState<Button>.completed(Button.init(
title: "Login",
enabled: false)))
var mutableNewModel = oldModel
mutableNewModel.title = initialState.title
mutableNewModel.credendials.usernameField.text = initialState.username
mutableNewModel.buttonState = initialState.buttonState
Lens<A,B> + Lens<B,C> = Lens<A,C>
extension Lens {
func compose<Subpart>(_ other: Lens<Part,Subpart>) -> Lens<Whole,Subpart> {
/// some code
}
}
extension Prism {
func compose<Subpart>(_ other: Prism<Part,Subpart>) -> Prism<Whole,Subpart> {
/// some code
}
}
let titleLens = LoginPage.lens.title
let usernameTextLens = LoginPage.lens.credentials
.compose(CredentialBox.lens.usernameField)
.compose(TextField.lens.text)
let buttonStateLens = LoginPage.lens.buttonState
let newModel = titleLens.set(initialState.title)
(usernameTextLens.set(initialState.username)
(buttonStateLens.set(initialState.buttonState)
(oldModel)))
Lens<A,B1> + Lens<A,B2> = Lens<A,(B1,B2)>
extension Lens {
static func zip<Part1,Part2>(
_ a: Lens<Whole,Part1>,
_ b: Lens<Whole,Part2>)
-> Lens<Whole,(Part1,Part2)>
where Part == (Part1,Part2)
{
/// some code
}
}
extension Prism {
static func zip<Part1,Part2>(
_ a: Prism<Whole,Part1>,
_ b: Prism<Whole,Part2>)
-> Prism<Whole,Either<Part1,Part2>>
where Part == Either<Part1,Part2>
{
/// some code
}
}
let initialStateLens = Lens.zip(
titleLens,
usernameTextLens,
buttonStateLens)
let newModel = initialStateLens.set(initialState)(oldModel)
What
about
prisms?
func advanceProcessingMessage(_ previous: String) -> String {
switch previous {
case "Please wait":
return "Almost there"
case "Almost there":
return "ALMOST THERE"
default:
return previous + "!"
}
}
extension Lens {
func modify(_ transform: (Part) -> Part) -> (Whole) -> Whole {
/// some code
}
}
extension Prism {
func tryModify(_ transform: (Part) -> Part) -> (Whole) -> Whole {
/// some code
}
}
/// Prism<ViewState<Button>,String>
let processingPrism = ViewState<Button>.prism.processing
let modifyLoginPage: ((ViewState<Button>) -> ViewState<Button>)
-> (LoginPage) -> LoginPage
modifyLoginPage = buttonStateLens.modify
let modifyProcessingMessage: ((String) -> String)
-> (ViewState<Button>) -> ViewState<Button>
modifyProcessingMessage = processingPrism.tryModify
/// Prism<ViewState<Button>,String>
let processingPrism = ViewState<Button>.prism.processing
let modifyLoginPage: ((ViewState<Button>) -> ViewState<Button>)
-> (LoginPage) -> LoginPage
modifyLoginPage = buttonStateLens.modify
let modifyProcessingMessage: ((String) -> String)
-> (ViewState<Button>) -> ViewState<Button>
modifyProcessingMessage = processingPrism.tryModify
(A -> B) + (B -> C) = (A -> C)
infix operator >>>
func >>> <A,B,C> (
_ left: @escaping (A) -> B,
_ right: @escaping (B) -> C)
-> (A) -> C
{
return { right(left($0)) }
}
let onProcessing: ((String) -> String) -> (LoginPage) -> LoginPage
onProcessing = modifyProcessingMessage >>> modifyLoginPage
let newModel = onProcessing(advanceProcessingMessage)(oldModel)
Let's recap
→ separated logic for accessing and mutating data;
→ defined simple, composable atomic objects;
→ built more complex objects just by combination;
→ transformed data with multiple, independent
pieces;
→ types are the only interface;
→ nothing will break if types don't change;
→ are we sure?
Buggy
lenses?
LAWS
Laws
→ required when building large systems
from small pieces
→ we need to trust the pieces
→ they are implicit in tests
→ let's define them explicitly for Lenses
and Prisms
Laws: Lens
→ getSet: the whole stays the same
→ setGet: the part stays the same
→ setSet: set is idempotent
Laws: Prisms
→ tryGetInject
→ injectTryGet
struct LensLaw {
static func setGet<Whole, Part>(
lens: Lens<Whole,Part>,
whole: Whole,
part: Part)
-> Bool where Part: Equatable
{
return lens.get(lens.set(part)(whole)) == part
}
}
Do we need to test ALL lenses and
prisms?
→ trivial lenses have always the same
structure;
→ if written by hand, tests can be useful;
→ lots of boilerplate;
→ a perfect fit for code generation;
→ Sourcery
Deriving
Lens from
KeyPath
extension WritableKeyPath {
var lens: Lens<Root,Value> {
return Lens<Root,Value>.init(
get: { root in
root[keyPath: self]
},
set: { value in
{ root in
var mutableRoot = root
mutableRoot[keyPath: self] = value
return mutableRoot
}
}
)
}
}
let passwordLens = (LoginPage.credentials.passwordField.text).lens
Non-trivial lenses and prisms
→ outputs of combinators;
→ particular data structures.
extension Dictionary {
static func lens(at key: Key) -> Lens<Dictionary,Value?> {
return Lens<Dictionary,Value?>(
get: { dict in
dict[key]
},
set: { value in
{ dict in
var mutableDict = dict
mutableDict[key] = value
return mutableDict
}
}
)
}
}
extension Dictionary {
static func lens(at key: Key) -> Lens<Dictionary,Value?> {
return Lens<Dictionary,Value?>(
get: { dict in
dict[key]
},
set: { value in
{ dict in
var mutableDict = dict
mutableDict[key] = value
return mutableDict
}
}
)
}
}
Lens<A,B?> + Lens<B,C> = ?
extension Optional {
static var prism: Prism<Optional,Wrapped> {
return Prism<Optional,Wrapped>.init(
tryGet: { $0 },
inject: Optional.some
)
}
}
Lens<A,B?> + Prism<B?,B> + Lens<B,C> = ?
struct Affine<Whole,Part> {
let tryGet: (Whole) -> Part?
let trySet: (Part) -> (Whole) -> Whole?
}
/// laws are similar to lens'
/// es. Affine to an index of an Array
Lens<A,B> + Prism<B,C> = Affine<A,C>
Lens<A,B> -> Affine<A,B>
Prism<A,B> -> Affine<A,B>
Lens<A,B?> + Prism<B?,B> +
Lens<B,C> =
Affine<A,B> + Lens<B,C> =
Affine<A,B> + Affine<B,C> =
Affine<A,C>
FunctionalKit library
https://github.com/facile-it/FunctionalKit
→ Lens, Prism, Affine definitions
→ some combinators
→ Law functions
Thanks
Links and Contacts
→ @_logicist
→ https://github.com/broomburgo/
Lenses-and-Prisms-in-Swift
→ https://github.com/facile-it/
FunctionalKit
→ Brandon Williams's original talk on
lenses: https://youtu.be/ofjehH9f-CU

More Related Content

What's hot

Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeAijaz Ansari
 
Stay with React.js in 2020
Stay with React.js in 2020Stay with React.js in 2020
Stay with React.js in 2020Jerry Liao
 
The Ring programming language version 1.8 book - Part 13 of 202
The Ring programming language version 1.8 book - Part 13 of 202The Ring programming language version 1.8 book - Part 13 of 202
The Ring programming language version 1.8 book - Part 13 of 202Mahmoud Samir Fayed
 
Beginning PHPUnit
Beginning PHPUnitBeginning PHPUnit
Beginning PHPUnitJace Ju
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testingVisual Engineering
 
Wwe Management System
Wwe Management SystemWwe Management System
Wwe Management SystemNeerajMudgal1
 
The Ring programming language version 1.9 book - Part 15 of 210
The Ring programming language version 1.9 book - Part 15 of 210The Ring programming language version 1.9 book - Part 15 of 210
The Ring programming language version 1.9 book - Part 15 of 210Mahmoud Samir Fayed
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionKent Huang
 
Chapter 8- Advanced Views and URLconfs
Chapter 8- Advanced Views and URLconfsChapter 8- Advanced Views and URLconfs
Chapter 8- Advanced Views and URLconfsVincent Chien
 
Mobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. БолеутоляющееMobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. БолеутоляющееMobileFest2018
 
Javascript Common Design Patterns
Javascript Common Design PatternsJavascript Common Design Patterns
Javascript Common Design PatternsPham Huy Tung
 
Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.Kuldeep Jain
 
Logic Equations Resolver J Script
Logic Equations Resolver   J ScriptLogic Equations Resolver   J Script
Logic Equations Resolver J ScriptRoman Agaev
 
Tugas praktikukm pemrograman c++
Tugas praktikukm  pemrograman c++Tugas praktikukm  pemrograman c++
Tugas praktikukm pemrograman c++Dendi Riadi
 
Creating Ext JS Extensions and Components
Creating Ext JS Extensions and ComponentsCreating Ext JS Extensions and Components
Creating Ext JS Extensions and ComponentsSencha
 

What's hot (20)

Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
 
Swing database(mysql)
Swing database(mysql)Swing database(mysql)
Swing database(mysql)
 
Stay with React.js in 2020
Stay with React.js in 2020Stay with React.js in 2020
Stay with React.js in 2020
 
My java file
My java fileMy java file
My java file
 
The Ring programming language version 1.8 book - Part 13 of 202
The Ring programming language version 1.8 book - Part 13 of 202The Ring programming language version 1.8 book - Part 13 of 202
The Ring programming language version 1.8 book - Part 13 of 202
 
Beginning PHPUnit
Beginning PHPUnitBeginning PHPUnit
Beginning PHPUnit
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
 
Wwe Management System
Wwe Management SystemWwe Management System
Wwe Management System
 
The Ring programming language version 1.9 book - Part 15 of 210
The Ring programming language version 1.9 book - Part 15 of 210The Ring programming language version 1.9 book - Part 15 of 210
The Ring programming language version 1.9 book - Part 15 of 210
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 Function
 
Chapter 8- Advanced Views and URLconfs
Chapter 8- Advanced Views and URLconfsChapter 8- Advanced Views and URLconfs
Chapter 8- Advanced Views and URLconfs
 
Spock's New Tricks
Spock's New TricksSpock's New Tricks
Spock's New Tricks
 
Mobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. БолеутоляющееMobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. Болеутоляющее
 
Javascript Common Design Patterns
Javascript Common Design PatternsJavascript Common Design Patterns
Javascript Common Design Patterns
 
guice-servlet
guice-servletguice-servlet
guice-servlet
 
Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.Chat application in java using swing and socket programming.
Chat application in java using swing and socket programming.
 
Logic Equations Resolver J Script
Logic Equations Resolver   J ScriptLogic Equations Resolver   J Script
Logic Equations Resolver J Script
 
Tugas praktikukm pemrograman c++
Tugas praktikukm  pemrograman c++Tugas praktikukm  pemrograman c++
Tugas praktikukm pemrograman c++
 
Creating Ext JS Extensions and Components
Creating Ext JS Extensions and ComponentsCreating Ext JS Extensions and Components
Creating Ext JS Extensions and Components
 
SOLID PRINCIPLES
SOLID PRINCIPLESSOLID PRINCIPLES
SOLID PRINCIPLES
 

Similar to Lenses and Prisms in Swift - Elviro Rocca - Codemotion Rome 2018

How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptKaty Slemon
 
준비하세요 Angular js 2.0
준비하세요 Angular js 2.0준비하세요 Angular js 2.0
준비하세요 Angular js 2.0Jeado Ko
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentationipolevoy
 
react-hooks.pdf
react-hooks.pdfreact-hooks.pdf
react-hooks.pdfchengbo xu
 
Murach : How to work with session state and cookies
Murach : How to work with session state and cookiesMurach : How to work with session state and cookies
Murach : How to work with session state and cookiesMahmoudOHassouna
 
Svcc Building Rich Applications with Groovy's SwingBuilder
Svcc Building Rich Applications with Groovy's SwingBuilderSvcc Building Rich Applications with Groovy's SwingBuilder
Svcc Building Rich Applications with Groovy's SwingBuilderAndres Almiray
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Ted Kulp
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETTomas Jansson
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingVisual Engineering
 
React new features and intro to Hooks
React new features and intro to HooksReact new features and intro to Hooks
React new features and intro to HooksSoluto
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
Introduction to Everit Component Registry - B Zsoldos
Introduction to Everit Component Registry - B ZsoldosIntroduction to Everit Component Registry - B Zsoldos
Introduction to Everit Component Registry - B Zsoldosmfrancis
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescriptDavid Furber
 

Similar to Lenses and Prisms in Swift - Elviro Rocca - Codemotion Rome 2018 (20)

Os Secoske
Os SecoskeOs Secoske
Os Secoske
 
How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescript
 
준비하세요 Angular js 2.0
준비하세요 Angular js 2.0준비하세요 Angular js 2.0
준비하세요 Angular js 2.0
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
 
react-hooks.pdf
react-hooks.pdfreact-hooks.pdf
react-hooks.pdf
 
Murach : How to work with session state and cookies
Murach : How to work with session state and cookiesMurach : How to work with session state and cookies
Murach : How to work with session state and cookies
 
Svcc Building Rich Applications with Groovy's SwingBuilder
Svcc Building Rich Applications with Groovy's SwingBuilderSvcc Building Rich Applications with Groovy's SwingBuilder
Svcc Building Rich Applications with Groovy's SwingBuilder
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
 
Griffon @ Svwjug
Griffon @ SvwjugGriffon @ Svwjug
Griffon @ Svwjug
 
Spring hibernate jsf_primefaces_intergration
Spring hibernate jsf_primefaces_intergrationSpring hibernate jsf_primefaces_intergration
Spring hibernate jsf_primefaces_intergration
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
React new features and intro to Hooks
React new features and intro to HooksReact new features and intro to Hooks
React new features and intro to Hooks
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Introduction to Everit Component Registry - B Zsoldos
Introduction to Everit Component Registry - B ZsoldosIntroduction to Everit Component Registry - B Zsoldos
Introduction to Everit Component Registry - B Zsoldos
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
Vaadin7
Vaadin7Vaadin7
Vaadin7
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescript
 
An introduction to Vue.js
An introduction to Vue.jsAn introduction to Vue.js
An introduction to Vue.js
 

More from Codemotion

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Codemotion
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyCodemotion
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaCodemotion
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserCodemotion
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Codemotion
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Codemotion
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Codemotion
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 - Codemotion
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Codemotion
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Codemotion
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Codemotion
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Codemotion
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Codemotion
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Codemotion
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Codemotion
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...Codemotion
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Codemotion
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Codemotion
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Codemotion
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Codemotion
 

More from Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Recently uploaded

SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 

Recently uploaded (20)

SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort ServiceHot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 

Lenses and Prisms in Swift - Elviro Rocca - Codemotion Rome 2018

  • 1. Lenses and Prisms in Swift This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/ 3.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
  • 3. Lenses and Prisms → encapsulate a relationship between a data structure and its parts → simple to define → composition tools → build powerful abstractions
  • 4.
  • 5.
  • 6.
  • 7. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 8. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 9. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 10. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 11. enum ViewState<T> { case empty case processing(String) case failed(Error) case completed(T) }
  • 12. enum ViewState<T> { case empty case processing(String) case failed(Error) case completed(T) }
  • 13. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 14. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 15. struct Lens<Whole,Part> { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } struct Prism<Whole,Part> { let tryGet: (Whole) -> Part? let inject: (Part) -> Whole }
  • 16.
  • 17. View
  • 20. struct LoginPage { var title: String var credendials: CredentialBox var buttonState: ViewState<Button> } struct CredentialBox { var usernameField: TextField var passwordField: TextField } struct TextField { var text: String var placeholder: String? var secureText: Bool } struct Button { var title: String var enabled: Bool }
  • 21. struct LoginPage { var title: String var credendials: CredentialBox var buttonState: ViewState<Button> } struct CredentialBox { var usernameField: TextField var passwordField: TextField } struct TextField { var text: String var placeholder: String? var secureText: Bool } struct Button { var title: String var enabled: Bool }
  • 22. extension CredentialBox { enum lens { static var usernameField: Lens<CredentialBox,TextField> { return Lens<CredentialBox,TextField>.init( get: { whole in whole.usernameField }, set: { part in { whole in var mutableWhole = whole mutableWhole.usernameField = part return mutableWhole } } ) } } }
  • 23. extension ViewState { enum prism { static var processing: Prism<ViewState,String> { return .init( tryGet: { whole in guard case .processing(let message) = whole else { return nil } return message }, inject: { part in .processing(part) } ) } } }
  • 24. Manipulate the model → a previous model exists → set a greeting title → set a stored username → button initially not enabled
  • 25. let initialState = ( title: "Welcome back!", username: savedUsername, buttonState: ViewState<Button>.completed(Button.init( title: "Login", enabled: false))) var mutableNewModel = oldModel mutableNewModel.title = initialState.title mutableNewModel.credendials.usernameField.text = initialState.username mutableNewModel.buttonState = initialState.buttonState
  • 26. let initialState = ( title: "Welcome back!", username: savedUsername, buttonState: ViewState<Button>.completed(Button.init( title: "Login", enabled: false))) var mutableNewModel = oldModel mutableNewModel.title = initialState.title mutableNewModel.credendials.usernameField.text = initialState.username mutableNewModel.buttonState = initialState.buttonState
  • 27. Lens<A,B> + Lens<B,C> = Lens<A,C>
  • 28. extension Lens { func compose<Subpart>(_ other: Lens<Part,Subpart>) -> Lens<Whole,Subpart> { /// some code } } extension Prism { func compose<Subpart>(_ other: Prism<Part,Subpart>) -> Prism<Whole,Subpart> { /// some code } }
  • 29. let titleLens = LoginPage.lens.title let usernameTextLens = LoginPage.lens.credentials .compose(CredentialBox.lens.usernameField) .compose(TextField.lens.text) let buttonStateLens = LoginPage.lens.buttonState
  • 30. let newModel = titleLens.set(initialState.title) (usernameTextLens.set(initialState.username) (buttonStateLens.set(initialState.buttonState) (oldModel)))
  • 31. Lens<A,B1> + Lens<A,B2> = Lens<A,(B1,B2)>
  • 32. extension Lens { static func zip<Part1,Part2>( _ a: Lens<Whole,Part1>, _ b: Lens<Whole,Part2>) -> Lens<Whole,(Part1,Part2)> where Part == (Part1,Part2) { /// some code } } extension Prism { static func zip<Part1,Part2>( _ a: Prism<Whole,Part1>, _ b: Prism<Whole,Part2>) -> Prism<Whole,Either<Part1,Part2>> where Part == Either<Part1,Part2> { /// some code } }
  • 33. let initialStateLens = Lens.zip( titleLens, usernameTextLens, buttonStateLens) let newModel = initialStateLens.set(initialState)(oldModel)
  • 35. func advanceProcessingMessage(_ previous: String) -> String { switch previous { case "Please wait": return "Almost there" case "Almost there": return "ALMOST THERE" default: return previous + "!" } }
  • 36. extension Lens { func modify(_ transform: (Part) -> Part) -> (Whole) -> Whole { /// some code } } extension Prism { func tryModify(_ transform: (Part) -> Part) -> (Whole) -> Whole { /// some code } }
  • 37. /// Prism<ViewState<Button>,String> let processingPrism = ViewState<Button>.prism.processing let modifyLoginPage: ((ViewState<Button>) -> ViewState<Button>) -> (LoginPage) -> LoginPage modifyLoginPage = buttonStateLens.modify let modifyProcessingMessage: ((String) -> String) -> (ViewState<Button>) -> ViewState<Button> modifyProcessingMessage = processingPrism.tryModify
  • 38. /// Prism<ViewState<Button>,String> let processingPrism = ViewState<Button>.prism.processing let modifyLoginPage: ((ViewState<Button>) -> ViewState<Button>) -> (LoginPage) -> LoginPage modifyLoginPage = buttonStateLens.modify let modifyProcessingMessage: ((String) -> String) -> (ViewState<Button>) -> ViewState<Button> modifyProcessingMessage = processingPrism.tryModify
  • 39. (A -> B) + (B -> C) = (A -> C)
  • 40. infix operator >>> func >>> <A,B,C> ( _ left: @escaping (A) -> B, _ right: @escaping (B) -> C) -> (A) -> C { return { right(left($0)) } }
  • 41. let onProcessing: ((String) -> String) -> (LoginPage) -> LoginPage onProcessing = modifyProcessingMessage >>> modifyLoginPage let newModel = onProcessing(advanceProcessingMessage)(oldModel)
  • 42. Let's recap → separated logic for accessing and mutating data; → defined simple, composable atomic objects; → built more complex objects just by combination; → transformed data with multiple, independent pieces; → types are the only interface; → nothing will break if types don't change; → are we sure?
  • 44. LAWS
  • 45. Laws → required when building large systems from small pieces → we need to trust the pieces → they are implicit in tests → let's define them explicitly for Lenses and Prisms
  • 46. Laws: Lens → getSet: the whole stays the same → setGet: the part stays the same → setSet: set is idempotent
  • 48. struct LensLaw { static func setGet<Whole, Part>( lens: Lens<Whole,Part>, whole: Whole, part: Part) -> Bool where Part: Equatable { return lens.get(lens.set(part)(whole)) == part } }
  • 49. Do we need to test ALL lenses and prisms? → trivial lenses have always the same structure; → if written by hand, tests can be useful; → lots of boilerplate; → a perfect fit for code generation; → Sourcery
  • 51. extension WritableKeyPath { var lens: Lens<Root,Value> { return Lens<Root,Value>.init( get: { root in root[keyPath: self] }, set: { value in { root in var mutableRoot = root mutableRoot[keyPath: self] = value return mutableRoot } } ) } } let passwordLens = (LoginPage.credentials.passwordField.text).lens
  • 52. Non-trivial lenses and prisms → outputs of combinators; → particular data structures.
  • 53. extension Dictionary { static func lens(at key: Key) -> Lens<Dictionary,Value?> { return Lens<Dictionary,Value?>( get: { dict in dict[key] }, set: { value in { dict in var mutableDict = dict mutableDict[key] = value return mutableDict } } ) } }
  • 54. extension Dictionary { static func lens(at key: Key) -> Lens<Dictionary,Value?> { return Lens<Dictionary,Value?>( get: { dict in dict[key] }, set: { value in { dict in var mutableDict = dict mutableDict[key] = value return mutableDict } } ) } }
  • 56. extension Optional { static var prism: Prism<Optional,Wrapped> { return Prism<Optional,Wrapped>.init( tryGet: { $0 }, inject: Optional.some ) } }
  • 57. Lens<A,B?> + Prism<B?,B> + Lens<B,C> = ?
  • 58. struct Affine<Whole,Part> { let tryGet: (Whole) -> Part? let trySet: (Part) -> (Whole) -> Whole? } /// laws are similar to lens' /// es. Affine to an index of an Array
  • 59. Lens<A,B> + Prism<B,C> = Affine<A,C>
  • 61. Lens<A,B?> + Prism<B?,B> + Lens<B,C> = Affine<A,B> + Lens<B,C> = Affine<A,B> + Affine<B,C> = Affine<A,C>
  • 62. FunctionalKit library https://github.com/facile-it/FunctionalKit → Lens, Prism, Affine definitions → some combinators → Law functions
  • 64. Links and Contacts → @_logicist → https://github.com/broomburgo/ Lenses-and-Prisms-in-Swift → https://github.com/facile-it/ FunctionalKit → Brandon Williams's original talk on lenses: https://youtu.be/ofjehH9f-CU