SlideShare a Scribd company logo
Optics with Monocle
Modeling the part and the whole
By Ilan Godik (@Nightra on IRC)
About me
▪ A CS Undergraduate at Haifa University
▪ A contributor to the Monocle library
▪ Functional programming lover.
What are lenses?
trait Lens[S,A]{
def get(s: S): A
def set(a: A)(s: S): S
}
In the simplest model, it's just a pair of a getter and a setter:
get
S
A1
S
A2
set
Lens[S, A]
A2
Classic lens example
person.copy(
address = person.address.copy(
street = person.address.street.copy(
name = person.address.street.name.capitalize
)
)
)
Updating nested structures is verbose and painful
case class Person(fullName: String, address: Address)
case class Address(city: String, street: Street)
case class Street(name: String, number: Int)
Monocle Lenses
(address composeLens street composeLens name).modify(_.capitalize)(person)
case class Person(fullName: String, address: Address)
case class Address(city: String, street: Street)
case class Street(name: String, number: Int)
val address = Lenser[Person](_.address)
val street = Lenser[Address](_.street)
val name = Lenser[Street](_.name)
Define lenses once, and compose as you wish
Lenses Macro annotation
(address composeLens street composeLens name).modify(_.capitalize)(person)
@Lenses case class Person(fullName: String, address: Address)
@Lenses case class Address(city: String, street: Street)
@Lenses case class Street(name: String, number: Int)
import Person._, Address._, Street._
Awesome, but not IDE friendly.
The object graph
Person
String Address
String Street
String Int
Code size growth
▪ Vanilla Scala: O(h2)
▪ Lenses: O(h)
Where h is the height of the object graph
Composition: Follow the arrows
Person
String Address
String Street
String Int
Lens composition
We compose lenses exactly how we would do it with copy.
S
set
Lens[S,A] compose Lens[A,B]
A
B2
get
S
A
B1
get B2
Lens composition
We compose lenses exactly how we would do it with copy.
S
set
Lens[S,A] compose Lens[A,B]
A
B2
get
S
A
B1
get B2
Lens composition
We compose lenses exactly how we would do it with copy.
S
set
Lens[S,A] compose Lens[A,B]
A
B2
get
S
A
B1
get B2
A
B2
Lens composition
We compose lenses exactly how we would do it with copy.
S
set
Lens[S,A] compose Lens[A,B]
A
B2
get
S
A
B1
get B2
A
B2
Polymorphic Lenses
Can we change the type of part of the structure while setting?
first.set("Hello")((1,2)) == ("Hello",2)
Polymorphic Lenses
Can we change the type of part of the structure while setting?
trait PLens[S, T, A, B] {
def get(s: S): A
def set(b: B)(s: S): T
} get
S
A
T
B
B
set
PLens[S, T, A, B]
Example: Unit conversion
Meters CM MM
?
Lens[Meters,CM]
Lens[Meters,MM]
Optics as different points of view of data
Isomorphisms
Do we get more power if our lens is bidirectional?
Meters CM MM
Iso[Meters,CM]
Iso[Meters,MM]
Isomorphisms
A B
Isomorphisms as a bijection: A function with an inverse
Prisms
What if we don’t have such a nice correspondence?
?
?
A B
Prisms
What if we don’t have such a nice correspondence?
?
?
IntString
A B
Prisms
What if we don’t have such a nice correspondence?
?
?
IntString
IntString
Option[Int]String
A B
Prisms
What if we don’t have such a nice correspondence?
?
?
IntString
IntString
Option[Int]String
Laws:
1. If there is an answer, going
back must give the source.
2. If we go back, there must
be an answer, which is
the source.
A B
Property Testing
Laws => Automated property testing
Int =String
Option[Int] =String
_.toString
Try(_.toInt).toOption
Property Testing
” .toInt = 9“
Property Testing
” .toInt = 9“
WAT
Prism Laws
?
IntString
A B
“9”
9
Example: Double binding
°C30 °F86
Iso[Celcius, Fahrenheit]
Prism[String, °F]Prism[String, °C]
Example: Double binding
°C30 °F86
Iso[Celcius, Fahrenheit]
Prism[String, °F]Prism[String, °C]
Example: Double binding
°C30 °F86
Iso[Celcius, Fahrenheit]
Prism[String, °F]Prism[String, °C]
A bit of theory:
Van Laarhoven Lenses
Is it possible to unify all the lens functions?
▪ get: S => A
▪ set: A => S => S
▪ modify: (A => A) => (S => S)
Is it possible to unify all the lens functions?
▪ get: S => A
▪ set: A => S => S
▪ modify: (A => A) => (S => S)
▪ modifyMaybe: (A => Option[A]) => (S => Option[S])
▪ modifyList: (A => List[A]) => (S => List[S])
A bit of theory:
Van Laarhoven Lenses
Functors
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
List Functor
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
Functor[List]{
def map[A,B](f: A => B)(list: List[A]): List[B] =
list.map(f)
}
Option Functor
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
Functor[Option]{
def map[A,B](f: A => B)(opt: Option[A]): Option[B] = opt match {
case None => None
case Some(a) => Some(f(a))
}
}
Van Laarhoven Lenses
The answer:
Functor[F] => (A => F[A]) => (S => F[S])
Van Laarhoven Lenses
The answer:
Functor[F] => (A => F[A]) => (S => F[S])
▪
▪
▪ :
▪ modifyMaybe: (A => Option[A]) => (S => Option[S])
▪ modifyList: (A => List[A]) => (S => List[S])
Van Laarhoven Lenses
The answer:
Functor[F] => (A => F[A]) => (S => F[S])
▪ get: S => A
▪ set: A => S => S
▪ modify: (A => A) => (S => S)
▪
▪
Van Laarhoven Lenses
The answer:
lens: Functor[F] => (A => F[A]) => (S => F[S])
type Id[A] = A
lens: (A => Id[A]) => (S => Id[S])
lens: (A => A) => (S => S)
modify = lens[Id]
Identity Functor
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
type Id[A] = A
Functor[Id]{
def map[A,B] (f: A => B)(a: Id[A]): Id[B]
}
Identity Functor
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
type Id[A] = A
Functor[Id]{
def map[A,B] (f: A => B)(a: Id[A]): Id[B]
def map[A,B] (f: A => B)(a: A): B = f(a)
}
Van Laarhoven Lenses
The answer:
lens: Functor[F] => (A => F[A]) => (S => F[S])
set(b) = modify(_ => b)
get: S => A = ???
Van Laarhoven Lenses
The answer:
lens: Functor[F] => (A => F[A]) => (S => F[S])
set(b) = modify(_ => b)
get: S => A = ???
Van Laarhoven Lenses
The answer:
lens: Functor[F] => (A => F[A]) => (S => F[S])
type Const[X][T] = X
F = Const[A]
lens: (A => Const[A][A]) => (S => Const[A][S])
lens: (A => A) => (S => A)
get = lens[Const[A]](a => a)
Const Functor
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
type Const[X][T] = X
Functor[Const[X]]{
def map[A,B] (f: A => B)(fa: Const[X][A]): Const[X][B]
}
Const Functor
trait Functor[F[_]]{
def map[A,B](f: A => B)(fa: F[A]): F[B]
}
type Const[X][T] = X
Functor[Const[X]]{
def map[A,B] (f: A => B)(fa: Const[X][A]): Const[X][B]
def map[A,B] (f: A => B)(x: X): X = x
}
Van Laarhoven Lenses
The answer:
Functor[F] => (A => F[A]) => (S => F[S])
▪ get: S => A
▪ set: A => S => S
▪ modify: (A => A) => (S => S)
▪ modifyMaybe: (A => Option[A]) => (S => Option[S])
▪ modifyList: (A => List[A]) => (S => List[S])
Creating Van Laarhoven Lenses
lens: Functor[F] => (A => F[A]) => (S => F[S])
def get: S => A
def set: A => S => S
def lens[F[_]:Functor](f: A => F[A])(s: S): F[S] =
f(get(s)). map (a => set(a)(s))
A
F[A]
(A => S) =>
F[A] => F[S]
(A => S)
F[S]
Shortly:
lens f s = f(get(s)).map(a => set(a)(s))
Creating Van Laarhoven Lenses
lens: Functor[F] => (A => F[A]) => (S => F[S])
type Id[A] = A
F = Id
lens: (A => A) => (S => S)
lens f s = f(get(s)).map(a => set(a)(s))
[ A ] [ A => S ]
modify f s = set(f(get(s)))(s)
set x s = modify(_ => x) s
= set(x)(s)
Creating Van Laarhoven Lenses
lens: Functor[F] => (A => F[A]) => (S => F[S])
type Const[A][X] = A
F = Const[A]
lens: (A => A) => (S => A)
lens f s = f(get(s)).map(a => set(a)(s))
[ A ] [ A => S ]
get’ f s = f(get(s))
get s = get’(id)(s) = get(s)
Monocle
▪ Provides lots of built-in optics and functions
▪ Macros for creating lenses
▪ Monocle used different models of lenses over time
▪ Current lens representation: PLens – Van Laarhoven hybrid.
▪ Performance: limited by scala function values – pretty good.
Resources
▪ Monocle on github
▪ Simon Peyton Jones’s lens talk at Scala Exchange 2013
▪ Edward Kmett on Lenses with the State Monad
Thank you!
Extra Slides
ASTs - Lenses for APIs
We can simplify our mental model with lenses
case class Person(fullName: String, address: Address)
Case class
decleration
Class
name
List[Field name -> Type]
ASTs - Lenses for APIs
We can simplify our mental model with lenses
case class Person(fullName: String, address: Address)
Case class
decleration
Class
name
List[Field name -> Type]
Public
constructor
Lens[Complex model, Simple model]
val
Polymorphic Optic Instances
How can we use the same lens for many types?
first.set("Hello")((1,2)) == ("Hello",2)
first.set("Hello")((1,2,3)) == ("Hello",2,3)
first.set("Hello")((1,2,3,4)) == ("Hello",2,3,4)
Example: Json
The structure of a specific Json object isn’t defined at the type system;
Each element can be a String or a Number or an Array or an Object.
We want to process Json assuming our specific structure, and let the system handle failures for
us.
We can define Prism[Json, String], Prism[Json, Double], Prism[Json, List[Json]]
and Prism[Json, Map[String, Json]].
Now we can compose these prisms to go deep inside a Json object and manipulate it.
* Polymorphic Lens Composition
get
S
A
T
B
B
set
PLens[S, T, A, B]
get
A
C
B
D
D
set
PLens[A, B, C, D]
get
S
C
T
D
D
set
PLens[S, T, C, D]

More Related Content

PDF
Beyond Scala Lens
PDF
λ | Lenses
PPTX
Taking your side effects aside
PDF
How to extend map? Or why we need collections redesign? - Scalar 2017
PPTX
The Essence of the Iterator Pattern
PPT
SDC - Einführung in Scala
PDF
Fp in scala with adts part 2
PDF
Type classes 101 - classification beyond inheritance
Beyond Scala Lens
λ | Lenses
Taking your side effects aside
How to extend map? Or why we need collections redesign? - Scalar 2017
The Essence of the Iterator Pattern
SDC - Einführung in Scala
Fp in scala with adts part 2
Type classes 101 - classification beyond inheritance

What's hot (20)

PDF
Pybelsberg — Constraint-based Programming in Python
PDF
Fp in scala with adts
PPTX
Running Free with the Monads
PDF
Scala Functional Patterns
PPT
Functional programming in scala
PDF
Why The Free Monad isn't Free
PDF
Hammurabi
PDF
Scala for Jedi
PDF
Monoids, monoids, monoids
PDF
A bit about Scala
PDF
Pythonic Graphics
PPTX
Introduction to Monads in Scala (2)
PPTX
Introduction to Monads in Scala (1)
PDF
Principled Error Handling with FP
PDF
Monoids, Monoids, Monoids - ScalaLove 2020
PDF
Atomically { Delete Your Actors }
PDF
Scala by Luc Duponcheel
PPTX
하스켈 프로그래밍 입문 3
PDF
Testing in the World of Functional Programming
PDF
Scala. Introduction to FP. Monads
Pybelsberg — Constraint-based Programming in Python
Fp in scala with adts
Running Free with the Monads
Scala Functional Patterns
Functional programming in scala
Why The Free Monad isn't Free
Hammurabi
Scala for Jedi
Monoids, monoids, monoids
A bit about Scala
Pythonic Graphics
Introduction to Monads in Scala (2)
Introduction to Monads in Scala (1)
Principled Error Handling with FP
Monoids, Monoids, Monoids - ScalaLove 2020
Atomically { Delete Your Actors }
Scala by Luc Duponcheel
하스켈 프로그래밍 입문 3
Testing in the World of Functional Programming
Scala. Introduction to FP. Monads
Ad

Similar to Optics with monocle - Modeling the part and the whole (20)

ODP
Scala lens: An introduction
PDF
San diego hug lens presentation
PPTX
Building Enigma with State Monad & Lens
PPTX
PDF
Functional microscope - Lenses in C++
PDF
Функциональный микроскоп: линзы в C++
PDF
Oh, All the things you'll traverse
PDF
Functional and Event Driven - another approach to domain modeling
PDF
Why functional programming and category theory strongly matters - Piotr Parad...
PDF
Why functional programming and category theory strongly matters
PDF
Introducing Monads and State Monad at PSUG
PDF
Scalar lenses-workshop
PDF
Lenses and Prisms in Swift - Elviro Rocca - Codemotion Rome 2018
PDF
Scala jargon cheatsheet
PDF
Practical cats
PPTX
Monads and friends demystified
PDF
Power of functions in a typed world
PDF
09. haskell Context
PPTX
Lenses for the masses - introducing Goggles
PDF
Functional optics
Scala lens: An introduction
San diego hug lens presentation
Building Enigma with State Monad & Lens
Functional microscope - Lenses in C++
Функциональный микроскоп: линзы в C++
Oh, All the things you'll traverse
Functional and Event Driven - another approach to domain modeling
Why functional programming and category theory strongly matters - Piotr Parad...
Why functional programming and category theory strongly matters
Introducing Monads and State Monad at PSUG
Scalar lenses-workshop
Lenses and Prisms in Swift - Elviro Rocca - Codemotion Rome 2018
Scala jargon cheatsheet
Practical cats
Monads and friends demystified
Power of functions in a typed world
09. haskell Context
Lenses for the masses - introducing Goggles
Functional optics
Ad

Recently uploaded (20)

PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
System and Network Administration Chapter 2
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PPTX
ai tools demonstartion for schools and inter college
PDF
How Creative Agencies Leverage Project Management Software.pdf
PPTX
Essential Infomation Tech presentation.pptx
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
Transform Your Business with a Software ERP System
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
top salesforce developer skills in 2025.pdf
PDF
medical staffing services at VALiNTRY
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Understanding Forklifts - TECH EHS Solution
Navsoft: AI-Powered Business Solutions & Custom Software Development
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
System and Network Administration Chapter 2
Which alternative to Crystal Reports is best for small or large businesses.pdf
Wondershare Filmora 15 Crack With Activation Key [2025
How to Choose the Right IT Partner for Your Business in Malaysia
Softaken Excel to vCard Converter Software.pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
ai tools demonstartion for schools and inter college
How Creative Agencies Leverage Project Management Software.pdf
Essential Infomation Tech presentation.pptx
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
VVF-Customer-Presentation2025-Ver1.9.pptx
Transform Your Business with a Software ERP System
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
top salesforce developer skills in 2025.pdf
medical staffing services at VALiNTRY
2025 Textile ERP Trends: SAP, Odoo & Oracle
Understanding Forklifts - TECH EHS Solution

Optics with monocle - Modeling the part and the whole

  • 1. Optics with Monocle Modeling the part and the whole By Ilan Godik (@Nightra on IRC)
  • 2. About me ▪ A CS Undergraduate at Haifa University ▪ A contributor to the Monocle library ▪ Functional programming lover.
  • 3. What are lenses? trait Lens[S,A]{ def get(s: S): A def set(a: A)(s: S): S } In the simplest model, it's just a pair of a getter and a setter: get S A1 S A2 set Lens[S, A] A2
  • 4. Classic lens example person.copy( address = person.address.copy( street = person.address.street.copy( name = person.address.street.name.capitalize ) ) ) Updating nested structures is verbose and painful case class Person(fullName: String, address: Address) case class Address(city: String, street: Street) case class Street(name: String, number: Int)
  • 5. Monocle Lenses (address composeLens street composeLens name).modify(_.capitalize)(person) case class Person(fullName: String, address: Address) case class Address(city: String, street: Street) case class Street(name: String, number: Int) val address = Lenser[Person](_.address) val street = Lenser[Address](_.street) val name = Lenser[Street](_.name) Define lenses once, and compose as you wish
  • 6. Lenses Macro annotation (address composeLens street composeLens name).modify(_.capitalize)(person) @Lenses case class Person(fullName: String, address: Address) @Lenses case class Address(city: String, street: Street) @Lenses case class Street(name: String, number: Int) import Person._, Address._, Street._ Awesome, but not IDE friendly.
  • 7. The object graph Person String Address String Street String Int
  • 8. Code size growth ▪ Vanilla Scala: O(h2) ▪ Lenses: O(h) Where h is the height of the object graph
  • 9. Composition: Follow the arrows Person String Address String Street String Int
  • 10. Lens composition We compose lenses exactly how we would do it with copy. S set Lens[S,A] compose Lens[A,B] A B2 get S A B1 get B2
  • 11. Lens composition We compose lenses exactly how we would do it with copy. S set Lens[S,A] compose Lens[A,B] A B2 get S A B1 get B2
  • 12. Lens composition We compose lenses exactly how we would do it with copy. S set Lens[S,A] compose Lens[A,B] A B2 get S A B1 get B2 A B2
  • 13. Lens composition We compose lenses exactly how we would do it with copy. S set Lens[S,A] compose Lens[A,B] A B2 get S A B1 get B2 A B2
  • 14. Polymorphic Lenses Can we change the type of part of the structure while setting? first.set("Hello")((1,2)) == ("Hello",2)
  • 15. Polymorphic Lenses Can we change the type of part of the structure while setting? trait PLens[S, T, A, B] { def get(s: S): A def set(b: B)(s: S): T } get S A T B B set PLens[S, T, A, B]
  • 16. Example: Unit conversion Meters CM MM ? Lens[Meters,CM] Lens[Meters,MM] Optics as different points of view of data
  • 17. Isomorphisms Do we get more power if our lens is bidirectional? Meters CM MM Iso[Meters,CM] Iso[Meters,MM]
  • 18. Isomorphisms A B Isomorphisms as a bijection: A function with an inverse
  • 19. Prisms What if we don’t have such a nice correspondence? ? ? A B
  • 20. Prisms What if we don’t have such a nice correspondence? ? ? IntString A B
  • 21. Prisms What if we don’t have such a nice correspondence? ? ? IntString IntString Option[Int]String A B
  • 22. Prisms What if we don’t have such a nice correspondence? ? ? IntString IntString Option[Int]String Laws: 1. If there is an answer, going back must give the source. 2. If we go back, there must be an answer, which is the source. A B
  • 23. Property Testing Laws => Automated property testing Int =String Option[Int] =String _.toString Try(_.toInt).toOption
  • 27. Example: Double binding °C30 °F86 Iso[Celcius, Fahrenheit] Prism[String, °F]Prism[String, °C]
  • 28. Example: Double binding °C30 °F86 Iso[Celcius, Fahrenheit] Prism[String, °F]Prism[String, °C]
  • 29. Example: Double binding °C30 °F86 Iso[Celcius, Fahrenheit] Prism[String, °F]Prism[String, °C]
  • 30. A bit of theory: Van Laarhoven Lenses Is it possible to unify all the lens functions? ▪ get: S => A ▪ set: A => S => S ▪ modify: (A => A) => (S => S)
  • 31. Is it possible to unify all the lens functions? ▪ get: S => A ▪ set: A => S => S ▪ modify: (A => A) => (S => S) ▪ modifyMaybe: (A => Option[A]) => (S => Option[S]) ▪ modifyList: (A => List[A]) => (S => List[S]) A bit of theory: Van Laarhoven Lenses
  • 33. List Functor trait Functor[F[_]]{ def map[A,B](f: A => B)(fa: F[A]): F[B] } Functor[List]{ def map[A,B](f: A => B)(list: List[A]): List[B] = list.map(f) }
  • 34. Option Functor trait Functor[F[_]]{ def map[A,B](f: A => B)(fa: F[A]): F[B] } Functor[Option]{ def map[A,B](f: A => B)(opt: Option[A]): Option[B] = opt match { case None => None case Some(a) => Some(f(a)) } }
  • 35. Van Laarhoven Lenses The answer: Functor[F] => (A => F[A]) => (S => F[S])
  • 36. Van Laarhoven Lenses The answer: Functor[F] => (A => F[A]) => (S => F[S]) ▪ ▪ ▪ : ▪ modifyMaybe: (A => Option[A]) => (S => Option[S]) ▪ modifyList: (A => List[A]) => (S => List[S])
  • 37. Van Laarhoven Lenses The answer: Functor[F] => (A => F[A]) => (S => F[S]) ▪ get: S => A ▪ set: A => S => S ▪ modify: (A => A) => (S => S) ▪ ▪
  • 38. Van Laarhoven Lenses The answer: lens: Functor[F] => (A => F[A]) => (S => F[S]) type Id[A] = A lens: (A => Id[A]) => (S => Id[S]) lens: (A => A) => (S => S) modify = lens[Id]
  • 39. Identity Functor trait Functor[F[_]]{ def map[A,B](f: A => B)(fa: F[A]): F[B] } type Id[A] = A Functor[Id]{ def map[A,B] (f: A => B)(a: Id[A]): Id[B] }
  • 40. Identity Functor trait Functor[F[_]]{ def map[A,B](f: A => B)(fa: F[A]): F[B] } type Id[A] = A Functor[Id]{ def map[A,B] (f: A => B)(a: Id[A]): Id[B] def map[A,B] (f: A => B)(a: A): B = f(a) }
  • 41. Van Laarhoven Lenses The answer: lens: Functor[F] => (A => F[A]) => (S => F[S]) set(b) = modify(_ => b) get: S => A = ???
  • 42. Van Laarhoven Lenses The answer: lens: Functor[F] => (A => F[A]) => (S => F[S]) set(b) = modify(_ => b) get: S => A = ???
  • 43. Van Laarhoven Lenses The answer: lens: Functor[F] => (A => F[A]) => (S => F[S]) type Const[X][T] = X F = Const[A] lens: (A => Const[A][A]) => (S => Const[A][S]) lens: (A => A) => (S => A) get = lens[Const[A]](a => a)
  • 44. Const Functor trait Functor[F[_]]{ def map[A,B](f: A => B)(fa: F[A]): F[B] } type Const[X][T] = X Functor[Const[X]]{ def map[A,B] (f: A => B)(fa: Const[X][A]): Const[X][B] }
  • 45. Const Functor trait Functor[F[_]]{ def map[A,B](f: A => B)(fa: F[A]): F[B] } type Const[X][T] = X Functor[Const[X]]{ def map[A,B] (f: A => B)(fa: Const[X][A]): Const[X][B] def map[A,B] (f: A => B)(x: X): X = x }
  • 46. Van Laarhoven Lenses The answer: Functor[F] => (A => F[A]) => (S => F[S]) ▪ get: S => A ▪ set: A => S => S ▪ modify: (A => A) => (S => S) ▪ modifyMaybe: (A => Option[A]) => (S => Option[S]) ▪ modifyList: (A => List[A]) => (S => List[S])
  • 47. Creating Van Laarhoven Lenses lens: Functor[F] => (A => F[A]) => (S => F[S]) def get: S => A def set: A => S => S def lens[F[_]:Functor](f: A => F[A])(s: S): F[S] = f(get(s)). map (a => set(a)(s)) A F[A] (A => S) => F[A] => F[S] (A => S) F[S] Shortly: lens f s = f(get(s)).map(a => set(a)(s))
  • 48. Creating Van Laarhoven Lenses lens: Functor[F] => (A => F[A]) => (S => F[S]) type Id[A] = A F = Id lens: (A => A) => (S => S) lens f s = f(get(s)).map(a => set(a)(s)) [ A ] [ A => S ] modify f s = set(f(get(s)))(s) set x s = modify(_ => x) s = set(x)(s)
  • 49. Creating Van Laarhoven Lenses lens: Functor[F] => (A => F[A]) => (S => F[S]) type Const[A][X] = A F = Const[A] lens: (A => A) => (S => A) lens f s = f(get(s)).map(a => set(a)(s)) [ A ] [ A => S ] get’ f s = f(get(s)) get s = get’(id)(s) = get(s)
  • 50. Monocle ▪ Provides lots of built-in optics and functions ▪ Macros for creating lenses ▪ Monocle used different models of lenses over time ▪ Current lens representation: PLens – Van Laarhoven hybrid. ▪ Performance: limited by scala function values – pretty good.
  • 51. Resources ▪ Monocle on github ▪ Simon Peyton Jones’s lens talk at Scala Exchange 2013 ▪ Edward Kmett on Lenses with the State Monad
  • 54. ASTs - Lenses for APIs We can simplify our mental model with lenses case class Person(fullName: String, address: Address) Case class decleration Class name List[Field name -> Type]
  • 55. ASTs - Lenses for APIs We can simplify our mental model with lenses case class Person(fullName: String, address: Address) Case class decleration Class name List[Field name -> Type] Public constructor Lens[Complex model, Simple model] val
  • 56. Polymorphic Optic Instances How can we use the same lens for many types? first.set("Hello")((1,2)) == ("Hello",2) first.set("Hello")((1,2,3)) == ("Hello",2,3) first.set("Hello")((1,2,3,4)) == ("Hello",2,3,4)
  • 57. Example: Json The structure of a specific Json object isn’t defined at the type system; Each element can be a String or a Number or an Array or an Object. We want to process Json assuming our specific structure, and let the system handle failures for us. We can define Prism[Json, String], Prism[Json, Double], Prism[Json, List[Json]] and Prism[Json, Map[String, Json]]. Now we can compose these prisms to go deep inside a Json object and manipulate it.
  • 58. * Polymorphic Lens Composition get S A T B B set PLens[S, T, A, B] get A C B D D set PLens[A, B, C, D] get S C T D D set PLens[S, T, C, D]