Lens Tutorial

What is a lens?

  • A getter and a setter
  • Actually, just a setter
  • forall f. Functor f => (a -> f b) -> s -> f t

What is a lens?

-- Given a way to get from `a` to `b`, and an `s`,
-- I'll give you a `t`
-- Think of `s` and `t` as "Big Values"
-- Think of `a` and `b` as "Small Values"
type Lens s t a b = forall f. Functor f 
  => (a -> f b) -> s -> f t

Simple Example

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

newtype Foo = Foo { unFoo :: Text }

transformFoo :: Functor f => (Text -> f Text) -> Foo -> f Foo
transformFoo f (Foo foo) = Foo <$> f foo

More Complicated Example

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

newtype FooA a = FooA { unFooA :: a }

transformFooA :: Functor f => (a -> f b) -> FooA a -> f (FooA b)
transformFooA f (FooA foo) = FooA <$> f foo

-- ZOMG it's been a lens this whole time
transformFooA' :: Lens (FooA a) (FooA b) a b
transformFooA' = transformFooA

In practice

-- get ~ view
get :: Lens s t a b -> s -> a
get l x = getConst $ l Const x

set :: Lens s t a b -> b -> s -> t
set l y x = runIdentity $ l (const $ Identity y) x

over :: Lens s t a b -> (a -> b) -> s -> t
over l f x = runIdentity $ l (Identity . f) x

Run your own effects

doAnEffect :: Functor f 
  => Lens s t a b -> (a -> f b) -> s -> f t
doAnEffect l f x = ???

Run your own effects

doAnEffect :: Functor f 
  => Lens s t a b -> (a -> f b) -> s -> f t
doAnEffect l f x = l f x

Traversals (prisms)

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

What?

  • Covariance preserves the ordering of types (≤), which orders types from more specific to more generic
  • Contravariance inverses this ordering

What?

-- functors are covariant
fmap :: (a -> b) -> (f a -> f b)
fmap show :: (Show a, Functor f) => f a -> f String

-- there are also contravariant functors
-- contravariance implies "could fail"
contramap :: (a -> b) -> (f b -> f a)
contramap show :: (Show a, Contravariant f) => f String -> f a

class Profunctor p where
  dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
  -- map the first argument contravariantly
  lmap :: (a -> b) -> p b c -> p a c
  -- map the second argument covariantly
  rmap :: (a -> b) -> p c a -> p c b

Profunctor -> Choice

-- p :: * -> * -> *
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

class Profunctor p => Choice p where
  left' :: p a b -> p (Either a c) (Either b c)
  right' :: p a b -> p (Either c a) (Either c b)

-- a prism is a "one-way lens" that always applies in one
-- direction (`b -> t`), and sometimes in the opposite 
-- direction (`s -> Either t a`)
prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
prism bt seta = dimap seta (either pure (fmap bt)) . right'

Traversals (prisms)

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

_Just :: (Applicative f, Choice p) 
  => p a (f b) -> p (Maybe a) (f (Maybe b))

instance Monoid m => Applicative (Const m)
_Just Const :: Monoid a => Maybe a -> Const a (Maybe b) -- get

instance Applicative Identity
_Just Identity :: Maybe a -> Identity (Maybe a) -- set

Lens

By dfithian

Lens

  • 297