SlideShare a Scribd company logo
1 of 45
Download to read offline
HASKELL
LENSES
SIVAJAYARAMAN
[2014-10-29WED]
0
WHAT?
Lenses (as a concept) are a way to focus and access
deeply into a complex structure.
"poking around inside things"
"access" here means read, write, modify, fold, traverse,
etc
lens is a package which provides an implementation of
the concept of lenses or functional references.
Availble through cabal: cabal install lens
There are many other lens packages but this is the one
we're going to look at today
We will only cover a subset in this session
Lens is a vast topic and needs a lot of time to
understand and use
Basic usage can be learnt quickly and the payoff is
worth it
WHY?
Convenience - will see later with an example
lens forms a combinator library and provides
composition, multiplicity, etc.
We'll see some of these behaviours here
It also provides a number of generalizations of lenses
including Prism, Traversal, Iso and Fold.
Can be used on many data types.
We'll see a few here such as record syntax, lists, etc
MOTIVATINGSIMPLE
EXAMPLE
Time to look at some code
SOMEBASICIDEASOFNOTE
A lens is a first class value that can be passed around like
any other data structure
lenses compose. We've seen in the example code where
we drill two levels down in a data structure through
compositon
The fact that they compose is very powerful and can
give rise to succint code that is more understandable
This is akin to 'dotted' notation in OO languages
although we're not quite modifying state
Some of the basic uses of lenses do not need the use of
this library
The lens library, of course, provides a lot of value
addition
So, how might we create a lens without using this library?
HOWMIGHTICREATEA
LENS
We saw an example of a simple usage of lens
In order to better understand lenses, let's try reinvent a
small part of the lens library
OUROWNBASICLENS
STARTINGOUT
For this purpose, we'll treat a Lens as a combination of a
getter/setter
data NaiveLens s a = NaiveLens { getL :: s -> a,
setL :: a -> s -> s}
-- view function to focus on a particular part of the data structure
view :: NaiveLens s a -> s -> a
-- set function to set a particular part of the data structure
set :: NaiveLens s a -> a -> s -> s
-- composing two lenses
:{
let composeNaiveLenses :: NaiveLens s1 s2 -> NaiveLens s2 a -> NaiveLens s1 a
composeNaiveLenses (NaiveLens getter1 setter1) (NaiveLens getter2 setter2)
= NaiveLens (getter2 . getter1) (a s -> setter1 (setter2 a (getter1 s)) s)
:}
USAGE
type TimeStamp = Integer
data FrameHeader = FrameHeader {
_frameNum :: FrameNumber,
_ts :: TimeStamp
} deriving Show
type FramePayload = String
data Frame = Frame {_header :: FrameHeader, _payload :: FramePayload} deriving Show
-- lens for each field
fheader :: NaiveLens Frame FrameHeader
ftimestamp :: NaiveLens FrameHeader TimeStamp
-- composed 'timestamp' lens
ftimestamp :: NaiveLens Frame TimeStamp
ftimestamp = fheader `composeNaiveLenses` ftimestamp
EXTENDING
What if we want to update a value instead of get or set?
We could implement it in terms of a get and then a set,
but that would be inefficient
We could add a function for update as part of the lens
definition!
data NaiveLens s a = NaiveLens { getL :: s -> a,
setL :: a -> s -> s,
updateL :: (a -> a) -> s -> s}
updateL :: NaiveLens s a -> (a -> a) -> s -> s
What if the function (a -> a) can fail, or need to do some
IO to get the new value?
We could then update NaiveLens with:
data NaiveLens s a = NaiveLens { getL :: s -> a,
setL :: a -> s -> s,
updateL :: (a -> a) -> s -> s
updateM :: (a -> Maybe a) -> s -> Maybe s
updateL :: (a -> IO a) -> s -> IO s}
Or, even generalize:
data NaiveLens s a = NaiveLens { getL :: s -> a,
setL :: a -> s -> s,
updateL :: (a -> a) -> s -> s
updateF :: Functor f => (a -> f a) -> s
-> f s}
AND,NOWFORSOMETHING
COMPLETELYDIFFERENT
EVENMOREGENERALIZATION
What if, we could turn this:
into this:
Note: I've not understood yet why we need the forall here
as the type compile even without it
data NaiveLens s a = NaiveLens { getL :: s -> a,
setL :: a -> s -> s,
updateL :: (a -> a) -> s -> s
updateF :: Functor f => (a -> f a) -> s -> f s}
:set -XRankNTypes -- forall needs 'RankNTypes' language extension
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
HOWDOESBETTERLENSWORK?
How is the type alias BetterLens even able to do the
things NaiveLens was doing?
What we need is a function like this for a setter
:{
-- Simply convert BetterLens to something that has the type of setL
let set :: BetterLens s a -> (a -> s -> s)
set lns a s = undefined
:}
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
By selecting functor for f above,Identity
:{
let set :: BetterLens s a -> (a -> s -> s)
set lns a s = runIdentity $ -- To unwrap the Identity functor.
-- Note that BetterLens gives f s
-- and we need s
lns (x -> Identity a) s
-- Note how we ignore the current value and
wrap 'a'
-- into Identity
-- set lns a = runIdentity . lns (Identity . const a)
:}
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
By selecting functor for f above,Identity
:{
-- The lens library calls 'modify' as 'over'
let over :: BetterLens s a -> (a -> a) -> s -> s
over lns f = runIdentity . lns (Identity . f)
:}
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
Now, how can this be useful for view?
view is of the type BetterLens s a -> (s -> a)
BetterLens is a type alias for a function that returns f
s)
What we need is a
So, we need something that goes from f s to a
How are we going to achieve that?
Can we somehow encode a into f?
INTRODUCINGTHECONSTFUNCTOR
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
Remember the const function we saw earlier?
const :: x -> y -> x
-- a function that takes two values, ignores the second and
-- gives back the first
The ( Functor is a functor that ignores its argument,
just like the const function did
Const v)
newtype Const x y = Const x
getConst :: Const x y -> x
getConst (Const x) = x
instance Functor (Const v) where
fmap f (Const x) = Const x
-- note that f is unused
We can use the Const functor to encode a into f
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
By selecting Const functor for f above,
:{
let view :: BetterLens s a -> (s -> a)
view lns s = getConst $ lns Const s
-- here, Const has type a -> Const a a
-- So, if Const a a is being used as the first argum
ent
-- of lns, it must be of type f a, with f being Cons
t a
:}
HOWTOMAKEALENS?
So far, we've been tiptoeing around the actual
implementation of the lenses
Now, let's do it
LENSFORTHEFRAMEHEADERCLASSWE
SAWBEFORE
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
type FrameNumber = Integer
type TimeStamp = Integer
data FrameHeader = FrameHeader {
_frameNum :: FrameNumber,
_ts :: TimeStamp
} deriving Show
frameNum :: BetterLens FrameHeader FrameNumber
-- frameNum :: Functor f => (FrameNumber -> f FrameNumber) ->
-- (FrameHeader -> f FrameHeader)
frameNum fn (FrameHeader frameNum' ts') = fmap (frameNum'' -> FrameHeader frameNum''
ts')
(fn frameNum')
SOMENOTES
The getConst doesn't have runtime cost
True given that the lens impl. (e.g. frameNum) and view
are inlined
Note that lenses do compose
COMPOSINGLENSES
type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
composeL :: BetterLens w1 w2 -> BetterLens w2 a -> BetterLens w1 a
We can rewrite this
-- lens1 :: (w2 -> f w2> -> (w1 -> f w1)
type lens1 = BetterLens w1 w2
-- lens2 :: (a -> f a> -> (w2 -> f w2)
type lens2 = BetterLens w2 a
-- tada
lens1 . lens2 :: (a -> f a) -> (w1 -> f w1)
So, lens composition is simply function composition
WHAT'SINANAME
Let's change our type synonym's name to
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
This version of lens that takes two type variables as
parameters is defined in Lens library
There is also another version
type Lens s t a b = forall f . Functor f => (a -> f b) -> s -> f t
we won't go much into this
HELPERTOCREATELENSES
If we look at the lens we created above:
frameNum :: Lens' FrameHeader FrameNumber
frameNum fn (frameNum' ts') = fmap (frameNum'' -> FrameHeader frameNum'' ts')
(fn frameNum')
it can also be created using the lens helper function
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
-- for the case where type of a & b are same and type of s & t are same
lens :: (s -> a) -> (s -> a -> s) -> Lens s s a a
-- or
lens :: (s -> a) -> (s -> a -> s) -> Lens' s a
frameNum = lens ((FrameHeader fnum _) -> fnum)
((FrameHeader _ ts') newFnum -> FrameHeader newFnum ts)
AUTOMATICCREATIONOFLENSES
If we look at the lens we created above:
frameNum :: Lens' FrameHeader FrameNumber
frameNum fn (frameNum' ts') = fmap (frameNum'' -> FrameHeader frameNum'' ts')
(fn frameNum')
-- or
frameNum = lens ((FrameHeader fnum _) -> fnum)
((FrameHeader _ ts') newFnum -> FrameHeader newFnum ts)
the implementation of frameNum is just boiler-plate code.
lens library comes with template haskell code to automate
this
import Control.Lens.TH
data FrameHeader = FrameHeader {
_frameNum :: FrameNumber,
_ts :: TimeStamp
} deriving Show
makeLenses ''FrameHeader
This creates two lenses frameNum and ts like the ones
discussed previously
AUTOMATICCREATIONOFLENSES
WITHOUTAPPENDAGES
What if you don't like the underscores in field names that TH
requires?
There are many variations of TH code that you can use to
make these lenses
One variation is something like
import Control.Lens.TH
data FrameHeader = FrameHeader {
frameNum :: FrameNumber,
ts :: TimeStamp
} deriving Show
makeLensesFor [("frameNum", "frameNumLens"), ("ts", "tsLens")] ''FrameHeader
which creates lenses frameNumLens and tsLens from the
above data structure
SHORTHAND
The lens library contains many `infix` versions of functions
such as set and view to make it look more imperative.
We're not going over those in this session
ASIMPLETWISTTOLENSES
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
What if, we change f from a Functor to an Applicative?
type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s
We get an entirely different thing which can 'focus' on
multiple things of type a
REMINDEROFALENS
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
data Person = Person { firstName :: String,
lastName :: String,
age :: Integer }
fnLens :: Lens' Person String
fnLens fn (fname' lname' age') = fmap (fname'' -> Person fname'' lname' age') (fn fna
me')
ATRAVERSAL
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s
nTraversal :: Traversal' Person String
-- nTraversal :: Applicative f => (String -> f String) -> (Person -> f Person)
nTraversal fn (Person fname' lname' age') = ... -- What can this be?
(fname'' lname'' -> Person fname'' lname'
' age')
... -- What can this be?
(fn fname')
... -- what can this be?
(fn lname')
AHA!
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s
nTraversal :: Traversal' Person String
-- nTraversal :: Applicative f => (String -> f String) -> (Person -> f Person)
nTraversal fn (Person fname' lname' age') = pure
(fname'' lname'' -> Person fname'' lname'
' age')
<*>
(fn fname')
<*>
(fn lname')
WHATCANWEUSE
TRAVERSALSFOR?
Remember over? over can be used on traversals as well
type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s
over lns f = runIdentity . lns (Identity . f)
nTraversal :: Traversal' Person String
example:
-- Returns a Person with both firstName and lastName capitalized
over nTraversal (map toUpper) :: Person -> Person
WHATCANWEUSE
TRAVERSALSFOR?
Of course, Traversals can be used for anything
Traversable
Examples: changing all elements of a list, maps, trees
PRISMS
Lens focuses on a single element of a complex data type
Traversal focuses on multiple elemnts of a complex data
type
the focussed elements are all of the same type
But, what if we have an algebriac data type that has many
constructors?
This is where Prism comes in
PRISMS
Prisms are like
_left :: Lens' (Either a b) a
>> view _left $ Left ()
()
>> view _left $ Right ()
error!
if the above is possible. Of course it is not possible.
PRISMS
So, can we use Maybe?
_left :: Lens' (Either a b) (Maybe a)
>> view _left $ Left ()
Just ()
>> view _left $ Right ()
Nothing
The problem is if we try to compose another Lens with it.
How can we?
PRISMS
So, we should not encode a Maybe into a Lens. This is why
Prism exists
Let's look at two functions that operate over prisms:
preview :: Prism' s a -> s -> Maybe a
review :: Prism' s a -> a -> s
Let's look at a built-in prism _Left
_Left :: Prism' (Either a b) a
>> preview _Left $ Left 10
Just 10
>> preview _Left $ Right "oops"
Nothing
APRISMUSAGE
data CruelData = CruelData {_cruelData :: String} deriving Show
data Greet = Hello Integer | Cruel CruelData | World String deriving Show
data Overall = Overall {_greet :: Greet} deriving Show
makeLenses ''CruelData
makeLenses ''Overall
-- TH
makePrisms ''Greet
-- only upcases if Greet is Cruel. Otherwise returns Overall as is
upcaseCruelty :: Overall -> Overall
upcaseCruelty = (greet . _Cruel . cruelData) %~ (map toUpper)
CONTROL.LENSOPERATORS
There are tons of operators (over 100) in the Control.Lens
library. Here's a general navigation rule:
Those that begin with ^ are view-like
Those that begin with ~ are over-like or set-like
Those that contain . are somehow basic (like view)
Those that contain % take functions (like over)
Those that begin with = are like the ones that have ~ but
apply modifications to a State monad
SOMECONTROL.LENS
FUNCTIONS
We've seen the following before:
view, set, over, traverse. There are others that are
useful
toListOf, preview, _1, … _9, _head, _tail, _init, etc
SOMEEXAMPLEUSAGE:
import Data.Tree
let t1 = Node 1 [Node 2 [Node 3 [], Node 4 []], Node 5 []]
let t2 = Node 6 [Node 7 [Node 8 [], Node 9 []], Node 10 []]
let t3 = Node 11 []
toListOf (traverse . traverse) [t1, t2, t3]
[1,2,3,4,5,6,7,8,9,10,11]
SOMEEXAMPLEUSAGE:
import Data.Tree
let t1 = Node 1 [Node 2 [Node 3 [], Node 4 []], Node 5 []]
let t2 = Node 6 [Node 7 [Node 8 [], Node 9 []], Node 10 []]
let t3 = Node 11 []
toListOf (traverse . traverse) [t1, t2, t3]
[1,2,3,4,5,6,7,8,9,10,11]
CREDITS
Several StackOverflow questions
Simon Peyton Jones's talk on Lenses
Lens starter tutorial in FPComplete
Talk on Lenses, Folds and Traversals by Edward Kmett,
author of the lens library

More Related Content

What's hot

λ | Lenses
λ | Lensesλ | Lenses
λ | LensesOpen-IT
 
RHive tutorials - Basic functions
RHive tutorials - Basic functionsRHive tutorials - Basic functions
RHive tutorials - Basic functionsAiden Seonghak Hong
 
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Samuel Fortier-Galarneau
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript FunctionsBrian Moschel
 
Python decorators
Python decoratorsPython decorators
Python decoratorsAlex Su
 
Decorators in Python
Decorators in PythonDecorators in Python
Decorators in PythonBen James
 
Idiomatic Javascript (ES5 to ES2015+)
Idiomatic Javascript (ES5 to ES2015+)Idiomatic Javascript (ES5 to ES2015+)
Idiomatic Javascript (ES5 to ES2015+)David Atchley
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsGlobalLogic Ukraine
 
Javascript Arrow function
Javascript Arrow functionJavascript Arrow function
Javascript Arrow functiontanerochris
 
CCF #1: Taking the reins of your data with Hiera 5
CCF #1: Taking the reins of your data with Hiera 5CCF #1: Taking the reins of your data with Hiera 5
CCF #1: Taking the reins of your data with Hiera 5davidmogar
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 
Planet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance EnhancementPlanet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance Enhancementup2soul
 

What's hot (20)

Implode & Explode in PHP
Implode & Explode in PHPImplode & Explode in PHP
Implode & Explode in PHP
 
λ | Lenses
λ | Lensesλ | Lenses
λ | Lenses
 
Linux intro 5 extra: awk
Linux intro 5 extra: awkLinux intro 5 extra: awk
Linux intro 5 extra: awk
 
TreSQL
TreSQL TreSQL
TreSQL
 
RHive tutorials - Basic functions
RHive tutorials - Basic functionsRHive tutorials - Basic functions
RHive tutorials - Basic functions
 
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 
Python decorators
Python decoratorsPython decorators
Python decorators
 
Decorators in Python
Decorators in PythonDecorators in Python
Decorators in Python
 
Idiomatic Javascript (ES5 to ES2015+)
Idiomatic Javascript (ES5 to ES2015+)Idiomatic Javascript (ES5 to ES2015+)
Idiomatic Javascript (ES5 to ES2015+)
 
Les03
Les03Les03
Les03
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side Effects
 
Javascript Arrow function
Javascript Arrow functionJavascript Arrow function
Javascript Arrow function
 
Namespaces
NamespacesNamespaces
Namespaces
 
Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
 
CCF #1: Taking the reins of your data with Hiera 5
CCF #1: Taking the reins of your data with Hiera 5CCF #1: Taking the reins of your data with Hiera 5
CCF #1: Taking the reins of your data with Hiera 5
 
Les01
Les01Les01
Les01
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
Millionways
MillionwaysMillionways
Millionways
 
Planet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance EnhancementPlanet-HTML5-Game-Engine Javascript Performance Enhancement
Planet-HTML5-Game-Engine Javascript Performance Enhancement
 

Similar to San diego hug lens presentation

Functional Programming with JavaScript
Functional Programming with JavaScriptFunctional Programming with JavaScript
Functional Programming with JavaScriptMark Shelton
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introductionKnoldus Inc.
 
Getting started with ES6
Getting started with ES6Getting started with ES6
Getting started with ES6Nitay Neeman
 
State of the CFEngine 2018
State of the CFEngine 2018State of the CFEngine 2018
State of the CFEngine 2018Nick Anderson
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with ScalaNeelkanth Sachdeva
 
Semantics-Aware Trace Analysis [PLDI 2009]
Semantics-Aware Trace Analysis [PLDI 2009]Semantics-Aware Trace Analysis [PLDI 2009]
Semantics-Aware Trace Analysis [PLDI 2009]Kevin Hoffman
 
Introduction to idris
Introduction to idrisIntroduction to idris
Introduction to idrisConor Farrell
 
Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2JollyRogers5
 
Building Enigma with State Monad & Lens
Building Enigma with State Monad & LensBuilding Enigma with State Monad & Lens
Building Enigma with State Monad & LensTimothy Perrett
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scalapramode_ce
 
Mobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. БолеутоляющееMobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. БолеутоляющееMobileFest2018
 
Talk - Query monad
Talk - Query monad Talk - Query monad
Talk - Query monad Fabernovel
 
Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With ScalaKnoldus Inc.
 
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Ryan Weaver
 
Database Oracle Basic
Database Oracle BasicDatabase Oracle Basic
Database Oracle BasicKamlesh Singh
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
Zope component architechture
Zope component architechtureZope component architechture
Zope component architechtureAnatoly Bubenkov
 

Similar to San diego hug lens presentation (20)

Functional Programming with JavaScript
Functional Programming with JavaScriptFunctional Programming with JavaScript
Functional Programming with JavaScript
 
Lecture 3
Lecture 3Lecture 3
Lecture 3
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introduction
 
Getting started with ES6
Getting started with ES6Getting started with ES6
Getting started with ES6
 
State of the CFEngine 2018
State of the CFEngine 2018State of the CFEngine 2018
State of the CFEngine 2018
 
Lecture 4
Lecture 4Lecture 4
Lecture 4
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with Scala
 
Semantics-Aware Trace Analysis [PLDI 2009]
Semantics-Aware Trace Analysis [PLDI 2009]Semantics-Aware Trace Analysis [PLDI 2009]
Semantics-Aware Trace Analysis [PLDI 2009]
 
Introduction to idris
Introduction to idrisIntroduction to idris
Introduction to idris
 
Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2
 
Building Enigma with State Monad & Lens
Building Enigma with State Monad & LensBuilding Enigma with State Monad & Lens
Building Enigma with State Monad & Lens
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
Mobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. БолеутоляющееMobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Александр Корин. Болеутоляющее
 
Talk - Query monad
Talk - Query monad Talk - Query monad
Talk - Query monad
 
Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With Scala
 
Coding in Style
Coding in StyleCoding in Style
Coding in Style
 
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
 
Database Oracle Basic
Database Oracle BasicDatabase Oracle Basic
Database Oracle Basic
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Zope component architechture
Zope component architechtureZope component architechture
Zope component architechture
 

Recently uploaded

KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
software engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxsoftware engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxnada99848
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 

Recently uploaded (20)

KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
software engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxsoftware engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptx
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 

San diego hug lens presentation

  • 2. WHAT? Lenses (as a concept) are a way to focus and access deeply into a complex structure. "poking around inside things" "access" here means read, write, modify, fold, traverse, etc lens is a package which provides an implementation of the concept of lenses or functional references. Availble through cabal: cabal install lens There are many other lens packages but this is the one we're going to look at today We will only cover a subset in this session Lens is a vast topic and needs a lot of time to understand and use Basic usage can be learnt quickly and the payoff is worth it
  • 3. WHY? Convenience - will see later with an example lens forms a combinator library and provides composition, multiplicity, etc. We'll see some of these behaviours here It also provides a number of generalizations of lenses including Prism, Traversal, Iso and Fold. Can be used on many data types. We'll see a few here such as record syntax, lists, etc
  • 5. SOMEBASICIDEASOFNOTE A lens is a first class value that can be passed around like any other data structure lenses compose. We've seen in the example code where we drill two levels down in a data structure through compositon The fact that they compose is very powerful and can give rise to succint code that is more understandable This is akin to 'dotted' notation in OO languages although we're not quite modifying state Some of the basic uses of lenses do not need the use of this library The lens library, of course, provides a lot of value addition So, how might we create a lens without using this library?
  • 6. HOWMIGHTICREATEA LENS We saw an example of a simple usage of lens In order to better understand lenses, let's try reinvent a small part of the lens library
  • 8. STARTINGOUT For this purpose, we'll treat a Lens as a combination of a getter/setter data NaiveLens s a = NaiveLens { getL :: s -> a, setL :: a -> s -> s} -- view function to focus on a particular part of the data structure view :: NaiveLens s a -> s -> a -- set function to set a particular part of the data structure set :: NaiveLens s a -> a -> s -> s -- composing two lenses :{ let composeNaiveLenses :: NaiveLens s1 s2 -> NaiveLens s2 a -> NaiveLens s1 a composeNaiveLenses (NaiveLens getter1 setter1) (NaiveLens getter2 setter2) = NaiveLens (getter2 . getter1) (a s -> setter1 (setter2 a (getter1 s)) s) :}
  • 9. USAGE type TimeStamp = Integer data FrameHeader = FrameHeader { _frameNum :: FrameNumber, _ts :: TimeStamp } deriving Show type FramePayload = String data Frame = Frame {_header :: FrameHeader, _payload :: FramePayload} deriving Show -- lens for each field fheader :: NaiveLens Frame FrameHeader ftimestamp :: NaiveLens FrameHeader TimeStamp -- composed 'timestamp' lens ftimestamp :: NaiveLens Frame TimeStamp ftimestamp = fheader `composeNaiveLenses` ftimestamp
  • 10. EXTENDING What if we want to update a value instead of get or set? We could implement it in terms of a get and then a set, but that would be inefficient We could add a function for update as part of the lens definition! data NaiveLens s a = NaiveLens { getL :: s -> a, setL :: a -> s -> s, updateL :: (a -> a) -> s -> s} updateL :: NaiveLens s a -> (a -> a) -> s -> s
  • 11. What if the function (a -> a) can fail, or need to do some IO to get the new value? We could then update NaiveLens with: data NaiveLens s a = NaiveLens { getL :: s -> a, setL :: a -> s -> s, updateL :: (a -> a) -> s -> s updateM :: (a -> Maybe a) -> s -> Maybe s updateL :: (a -> IO a) -> s -> IO s}
  • 12. Or, even generalize: data NaiveLens s a = NaiveLens { getL :: s -> a, setL :: a -> s -> s, updateL :: (a -> a) -> s -> s updateF :: Functor f => (a -> f a) -> s -> f s}
  • 14. EVENMOREGENERALIZATION What if, we could turn this: into this: Note: I've not understood yet why we need the forall here as the type compile even without it data NaiveLens s a = NaiveLens { getL :: s -> a, setL :: a -> s -> s, updateL :: (a -> a) -> s -> s updateF :: Functor f => (a -> f a) -> s -> f s} :set -XRankNTypes -- forall needs 'RankNTypes' language extension type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s
  • 15. HOWDOESBETTERLENSWORK? How is the type alias BetterLens even able to do the things NaiveLens was doing? What we need is a function like this for a setter :{ -- Simply convert BetterLens to something that has the type of setL let set :: BetterLens s a -> (a -> s -> s) set lns a s = undefined :}
  • 16. type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s By selecting functor for f above,Identity :{ let set :: BetterLens s a -> (a -> s -> s) set lns a s = runIdentity $ -- To unwrap the Identity functor. -- Note that BetterLens gives f s -- and we need s lns (x -> Identity a) s -- Note how we ignore the current value and wrap 'a' -- into Identity -- set lns a = runIdentity . lns (Identity . const a) :}
  • 17. type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s By selecting functor for f above,Identity :{ -- The lens library calls 'modify' as 'over' let over :: BetterLens s a -> (a -> a) -> s -> s over lns f = runIdentity . lns (Identity . f) :}
  • 18. type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s Now, how can this be useful for view? view is of the type BetterLens s a -> (s -> a) BetterLens is a type alias for a function that returns f s) What we need is a So, we need something that goes from f s to a How are we going to achieve that? Can we somehow encode a into f?
  • 19. INTRODUCINGTHECONSTFUNCTOR type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s Remember the const function we saw earlier? const :: x -> y -> x -- a function that takes two values, ignores the second and -- gives back the first The ( Functor is a functor that ignores its argument, just like the const function did Const v) newtype Const x y = Const x getConst :: Const x y -> x getConst (Const x) = x instance Functor (Const v) where fmap f (Const x) = Const x -- note that f is unused We can use the Const functor to encode a into f
  • 20. type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s By selecting Const functor for f above, :{ let view :: BetterLens s a -> (s -> a) view lns s = getConst $ lns Const s -- here, Const has type a -> Const a a -- So, if Const a a is being used as the first argum ent -- of lns, it must be of type f a, with f being Cons t a :}
  • 21. HOWTOMAKEALENS? So far, we've been tiptoeing around the actual implementation of the lenses Now, let's do it
  • 22. LENSFORTHEFRAMEHEADERCLASSWE SAWBEFORE type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s type FrameNumber = Integer type TimeStamp = Integer data FrameHeader = FrameHeader { _frameNum :: FrameNumber, _ts :: TimeStamp } deriving Show frameNum :: BetterLens FrameHeader FrameNumber -- frameNum :: Functor f => (FrameNumber -> f FrameNumber) -> -- (FrameHeader -> f FrameHeader) frameNum fn (FrameHeader frameNum' ts') = fmap (frameNum'' -> FrameHeader frameNum'' ts') (fn frameNum')
  • 23. SOMENOTES The getConst doesn't have runtime cost True given that the lens impl. (e.g. frameNum) and view are inlined Note that lenses do compose
  • 24. COMPOSINGLENSES type BetterLens s a = forall f . Functor f => (a -> f a) -> s -> f s composeL :: BetterLens w1 w2 -> BetterLens w2 a -> BetterLens w1 a We can rewrite this -- lens1 :: (w2 -> f w2> -> (w1 -> f w1) type lens1 = BetterLens w1 w2 -- lens2 :: (a -> f a> -> (w2 -> f w2) type lens2 = BetterLens w2 a -- tada lens1 . lens2 :: (a -> f a) -> (w1 -> f w1) So, lens composition is simply function composition
  • 25. WHAT'SINANAME Let's change our type synonym's name to type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s This version of lens that takes two type variables as parameters is defined in Lens library There is also another version type Lens s t a b = forall f . Functor f => (a -> f b) -> s -> f t we won't go much into this
  • 26. HELPERTOCREATELENSES If we look at the lens we created above: frameNum :: Lens' FrameHeader FrameNumber frameNum fn (frameNum' ts') = fmap (frameNum'' -> FrameHeader frameNum'' ts') (fn frameNum') it can also be created using the lens helper function lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b -- for the case where type of a & b are same and type of s & t are same lens :: (s -> a) -> (s -> a -> s) -> Lens s s a a -- or lens :: (s -> a) -> (s -> a -> s) -> Lens' s a frameNum = lens ((FrameHeader fnum _) -> fnum) ((FrameHeader _ ts') newFnum -> FrameHeader newFnum ts)
  • 27. AUTOMATICCREATIONOFLENSES If we look at the lens we created above: frameNum :: Lens' FrameHeader FrameNumber frameNum fn (frameNum' ts') = fmap (frameNum'' -> FrameHeader frameNum'' ts') (fn frameNum') -- or frameNum = lens ((FrameHeader fnum _) -> fnum) ((FrameHeader _ ts') newFnum -> FrameHeader newFnum ts) the implementation of frameNum is just boiler-plate code. lens library comes with template haskell code to automate this import Control.Lens.TH data FrameHeader = FrameHeader { _frameNum :: FrameNumber, _ts :: TimeStamp } deriving Show makeLenses ''FrameHeader This creates two lenses frameNum and ts like the ones discussed previously
  • 28. AUTOMATICCREATIONOFLENSES WITHOUTAPPENDAGES What if you don't like the underscores in field names that TH requires? There are many variations of TH code that you can use to make these lenses One variation is something like import Control.Lens.TH data FrameHeader = FrameHeader { frameNum :: FrameNumber, ts :: TimeStamp } deriving Show makeLensesFor [("frameNum", "frameNumLens"), ("ts", "tsLens")] ''FrameHeader which creates lenses frameNumLens and tsLens from the above data structure
  • 29. SHORTHAND The lens library contains many `infix` versions of functions such as set and view to make it look more imperative. We're not going over those in this session
  • 30. ASIMPLETWISTTOLENSES type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s What if, we change f from a Functor to an Applicative? type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s We get an entirely different thing which can 'focus' on multiple things of type a
  • 31. REMINDEROFALENS type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s data Person = Person { firstName :: String, lastName :: String, age :: Integer } fnLens :: Lens' Person String fnLens fn (fname' lname' age') = fmap (fname'' -> Person fname'' lname' age') (fn fna me')
  • 32. ATRAVERSAL type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s nTraversal :: Traversal' Person String -- nTraversal :: Applicative f => (String -> f String) -> (Person -> f Person) nTraversal fn (Person fname' lname' age') = ... -- What can this be? (fname'' lname'' -> Person fname'' lname' ' age') ... -- What can this be? (fn fname') ... -- what can this be? (fn lname')
  • 33. AHA! type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s nTraversal :: Traversal' Person String -- nTraversal :: Applicative f => (String -> f String) -> (Person -> f Person) nTraversal fn (Person fname' lname' age') = pure (fname'' lname'' -> Person fname'' lname' ' age') <*> (fn fname') <*> (fn lname')
  • 34. WHATCANWEUSE TRAVERSALSFOR? Remember over? over can be used on traversals as well type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s over lns f = runIdentity . lns (Identity . f) nTraversal :: Traversal' Person String example: -- Returns a Person with both firstName and lastName capitalized over nTraversal (map toUpper) :: Person -> Person
  • 35. WHATCANWEUSE TRAVERSALSFOR? Of course, Traversals can be used for anything Traversable Examples: changing all elements of a list, maps, trees
  • 36. PRISMS Lens focuses on a single element of a complex data type Traversal focuses on multiple elemnts of a complex data type the focussed elements are all of the same type But, what if we have an algebriac data type that has many constructors? This is where Prism comes in
  • 37. PRISMS Prisms are like _left :: Lens' (Either a b) a >> view _left $ Left () () >> view _left $ Right () error! if the above is possible. Of course it is not possible.
  • 38. PRISMS So, can we use Maybe? _left :: Lens' (Either a b) (Maybe a) >> view _left $ Left () Just () >> view _left $ Right () Nothing The problem is if we try to compose another Lens with it. How can we?
  • 39. PRISMS So, we should not encode a Maybe into a Lens. This is why Prism exists Let's look at two functions that operate over prisms: preview :: Prism' s a -> s -> Maybe a review :: Prism' s a -> a -> s Let's look at a built-in prism _Left _Left :: Prism' (Either a b) a >> preview _Left $ Left 10 Just 10 >> preview _Left $ Right "oops" Nothing
  • 40. APRISMUSAGE data CruelData = CruelData {_cruelData :: String} deriving Show data Greet = Hello Integer | Cruel CruelData | World String deriving Show data Overall = Overall {_greet :: Greet} deriving Show makeLenses ''CruelData makeLenses ''Overall -- TH makePrisms ''Greet -- only upcases if Greet is Cruel. Otherwise returns Overall as is upcaseCruelty :: Overall -> Overall upcaseCruelty = (greet . _Cruel . cruelData) %~ (map toUpper)
  • 41. CONTROL.LENSOPERATORS There are tons of operators (over 100) in the Control.Lens library. Here's a general navigation rule: Those that begin with ^ are view-like Those that begin with ~ are over-like or set-like Those that contain . are somehow basic (like view) Those that contain % take functions (like over) Those that begin with = are like the ones that have ~ but apply modifications to a State monad
  • 42. SOMECONTROL.LENS FUNCTIONS We've seen the following before: view, set, over, traverse. There are others that are useful toListOf, preview, _1, … _9, _head, _tail, _init, etc
  • 43. SOMEEXAMPLEUSAGE: import Data.Tree let t1 = Node 1 [Node 2 [Node 3 [], Node 4 []], Node 5 []] let t2 = Node 6 [Node 7 [Node 8 [], Node 9 []], Node 10 []] let t3 = Node 11 [] toListOf (traverse . traverse) [t1, t2, t3] [1,2,3,4,5,6,7,8,9,10,11]
  • 44. SOMEEXAMPLEUSAGE: import Data.Tree let t1 = Node 1 [Node 2 [Node 3 [], Node 4 []], Node 5 []] let t2 = Node 6 [Node 7 [Node 8 [], Node 9 []], Node 10 []] let t3 = Node 11 [] toListOf (traverse . traverse) [t1, t2, t3] [1,2,3,4,5,6,7,8,9,10,11]
  • 45. CREDITS Several StackOverflow questions Simon Peyton Jones's talk on Lenses Lens starter tutorial in FPComplete Talk on Lenses, Folds and Traversals by Edward Kmett, author of the lens library