SlideShare uma empresa Scribd logo
1 de 45
Baixar para ler 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

Mais conteúdo relacionado

Mais procurados

Python decorators
Python decoratorsPython decorators
Python decorators
Alex Su
 
Decorators in Python
Decorators in PythonDecorators in Python
Decorators in Python
Ben James
 

Mais procurados (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
 

Semelhante a San diego hug lens presentation

Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
pramode_ce
 
Database Oracle Basic
Database Oracle BasicDatabase Oracle Basic
Database Oracle Basic
Kamlesh 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 Jasmine
Paulo Ragonha
 

Semelhante a 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
 
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
 
Introduction to CoffeeScript
Introduction to CoffeeScriptIntroduction to CoffeeScript
Introduction to CoffeeScript
 

Último

%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 

Último (20)

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 

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