Profunctor Optics

Overview

  • Algebraic Data Types
  • Lens Library
  • Functors
  • Profunctor Optics

lens

type Iso' s a =
  forall p f. (Profunctor p, Functor f) => p a (f a) -> p s (f s)

type Lens' s a =
  forall f. (Functor f) => (a -> f a) -> s -> f s

type Prism' s a =
  forall p f. (Choice p, Applicative f) => p a (f a) -> p s (f s)

type Traversal' s a =
  forall f. (Applicative f) => (a -> f a) -> s -> f s

type Fold s a =
  forall p f. (Contravariant f, Applicative f) => a (f a) -> s -> f s

purescript-profunctor-lenses

type IsoP s a =
  forall p. (Profunctor p) => p a a -> p s s

type LensP s a =
  forall p. (Strong p) => p a a -> p s s

type PrismP s a =
  forall p. (Choice p) => p a a -> p s s

type TraversalP s a =
  forall p. (Wander p) => p a a -> p s s

type FoldP r s a =
  Forget r a a -> Forget r s s

Algebraic Data Types

to the code...

Sum Types

data IorB = I Int | B Bool

Sum Types

data IorB = I Int | B Bool
type IorB' = Either Int Bool

-- `IorB <~> Either Int Bool`

--           IorB -> IorB'
matchIorB :: IorB -> Either Int Bool
matchIorB (I n) = Left n
matchIorB (B b) = Right b

--            IorB'           -> IorB
injectIorB :: Either Int Bool -> IorB
injectIorB (Left n)  = (I n)
injectIorB (Right b) = (B b)

Are isomorphic to Either

Sum Types

data IorB = I Int | B Bool

-- Sum examples

five :: IorB
five = I 5

truuu :: IorB
truuu = B True

Values of the Day:

Product Types

data Person = P
  { _pName :: String
  , _pAge  :: Int
  }

data AlsoPerson = AP String Int

Product Types

-- | `P String Int <~> (String, Int)`

type Person = (String,Int)

-- |      Person -> Person'
splitP :: Person -> (String, Int)
splitP (P name age) = (name, age)

-- |        Person'       -> Person
unsplitP :: (String, Int) -> Person
unsplitP (name, age) = P name age

Product Types

data Person = P
  { _pName :: String
  , _pAge  :: Int
  }

-- Values

john :: Person
john = P "John" 889

sue :: Person
sue = P "Sue" 407

Values of the Day:

Lens Library

Lens Library

  • Lenses
  • Prisms
  • Isos
  • Traversals
  • Folds

Lens Library

 

Challenge:

Given a list of homeowners, modify each homeowner's address by capitalizing each address' street name:

Lens Library

// Java

for (Homeowner owner : ArrayList<HomeOwner>) {
    person.address.street.name.toUpper()
}
-- Haskell

fmap updateHomeOwner homeowners
  where updateHomeOwner (HomeOwner name age address)
          = HomeOwner name age (updateAddress address)
        updateAddress (Address (Street no name) state zip))
          = Address (Street no (toUpper name)) state zip

Lens Library

-- Haskell

over (traverse.address.street.name) toUpper homeowners
// Java

for (Homeowner owner : ArrayList<HomeOwner>) {
    person.address.street.name.toUpper()
}

Lens Library

λ> view pName john
"John"
λ> view pName sue
"Sue"
λ> view pAge john
889
λ> view pAge sue
407
λ> set pAge 10 sue
P {_pName = "Sue", _pAge = 10}
λ> set pName "Sue" john
P {_pName = "Sue", _pAge = 889}
λ> over pAge (+111) john
P {_pName = "Sue", _pAge = 889}

Person lenses pName and ​pAge

john :: Person
john = P "John" 889

sue :: Person
sue = P "Sue" 407
pName :: Lens' Person String
pAge :: Lens' Person Int

Lens Library

λ> preview _I five
Just 5
λ> preview _B five
Nothing
λ> preview _I truuu
Nothing
λ> preview _B truuu
Just True
λ> review _B True
B True
λ> review _I 5
I 5
λ> over _I (+95) five
I 100

IorB prisms _I and ​_B

five :: IorB
five = I 5

truuu :: IorB
truuu = B True
_I :: Prism' IorB Int
_B :: Prism' IorB Bool

Functors

Functor

(Covariant)

class Functor f where
  fmap :: (a -> b) -> f a -> f b

a

b

a -> b

F

F

Functor

class Functor f where
  fmap :: (a -> b) -> f a -> f b
-- | `[x] = [] x` where f=`[]` and a=`x`
λ> fmap (+10) [1,2,3,4]
[11,12,13,14]


-- | `(x,y) = (,) x y` where f=`(x,)` and a=`y`
λ> fmap (+10) (1,2)
(1,12)

-- | `data Either x y = Left x | Right y` where
-- | f=`Either x` and a=`y`
λ> fmap (+10) (Left 1)
Left 1
λ> fmap (+10) (Right 2)
Right 12

Bifunctor

class Bifunctor p where
  bimap :: (a -> b) -> (c -> d) -> p a c -> p b d

a -> b

a

c

b

d

P

P

c -> d

-- | `(x,y) = (,) x y` where f=`(,)` and
-- | a=`x` and b=`y`
λ> bimap (+10) (+50) (1,1)
(11,51)

-- | `data Either x y = Left x | Right y` where
-- | f=`Either` a=`x` and b=`y`
λ> bimap (+10) (+50) (Left 1)
Left 11
λ> bimap (+10) (+50) (Right 1)
Right 51

Bifunctor

class Bifunctor p where
  bimap :: (a -> b) -> (c -> d) -> p a c -> p b d

Contravariant Functor

class Contravariant f where
  contramap :: (a -> b) -> f b -> f a

b

a -> b

F

Contravariant Functor

class Contravariant f where
  contramap :: (a -> b) -> f b -> f a

a -> b

b

F

a

F

Profunctor

 

class Profunctor p where
  dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
  lmap :: (a -> b) -> p b c -> p a c
  rmap :: (b -> c) -> p a b -> p a c

a -> b

b

c

P

c -> d

Profunctor

 

class Profunctor p where
  dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
  lmap :: (a -> b) -> p b c -> p a c
  rmap :: (b -> c) -> p a b -> p a c

a -> b

b

c

P

c -> d

Profunctor takes a "pre-computation", a "post-computation", and an intermediate relationship between
between things

Profunctor

 

class Profunctor p where
  dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
  lmap :: (a -> b) -> p b c -> p a c
  rmap :: (b -> c) -> p a b -> p a c

a -> b

b

c

P

c -> d

a

d

P

Strong Profunctor

 

-- | The "operate on a part of a whole" typeclass
class Profunctor p => Strong p where
    first' :: p a b -> p (a, q) (b, q)

Think of the following:

p a b as a relationship on a part
p (a,q) (b,q)  as a relationship on the whole

Strong Profunctor

 

-- | The "operate on a part of a whole" typeclass
class Profunctor p => Strong p where
    first' :: p a b -> p (a, q) (b, q)

a

b

P

(a,q)

(b,q)

P

Choice Profunctor

 

-- | The "operate on a branch of a
-- | possibility" typeclass
class Profunctor p => Choice p where
    left' :: p a b  -> p (Either a q) (Either b q)

Think of the following:

p a b as a relationship on a branch
p (Either a q) (Either b q)  as a relationship on all possibilities

Choice Profunctor

 

-- | The "operate on a branch of a
-- | possibility" typeclass
class Profunctor p => Choice p where
    left' :: p a b  -> p (Either a q) (Either b q)

a

b

P

Either a q

P

Either b q

to the code...

Profunctor Optics

Profunctor Optics

Simple Optics

Lens' inner outer and Prism' inner outer isomorphisms

https://blog.jle.im/entry/lenses-products-prisms-sums.html

Profunctor Optics

Lens Families

Lens s t a b and Prism s t a b isomorphisms, as a lens family

https://blog.jle.im/entry/lenses-products-prisms-sums.html

purescript-profunctor-lenses

type IsoP s a =
  forall p. (Profunctor p) => p a a -> p s s

type LensP s a =
  forall p. (Strong p) => p a a -> p s s

type PrismP s a =
  forall p. (Choice p) => p a a -> p s s

-- class (Strong p, Choice p) => Wander p where..
type TraversalP s a =
  forall p. (Wander p) => p a a -> p s s

type FoldP r s a =
  Forget r a a -> Forget r s s

Profunctor Optics

type Optic c s t a b = forall p. c p => p a b -> p s t
type Optic c s t a b = forall p. c p => p a b -> p s t

C = 

Strong

Traversing1

Choice

Bicontravariant

Bifunctor

Mapping

http://oleg.fi/gists/posts/2017-04-18-glassery.html

http://oleg.fi/gists/posts/2017-04-18-glassery.html

Profunctor Optics

By Heneli Kailahi

Profunctor Optics

  • 353