packages feed

generic-lens-1.0.0.0: README.md

# generic-lens

[![Build Status](https://travis-ci.org/kcsongor/generic-lens.svg?branch=master)](https://travis-ci.org/kcsongor/generic-lens)
[![Hackage](https://img.shields.io/hackage/v/generic-lens.svg)](https://hackage.haskell.org/package/generic-lens)

Generically derive traversals, lenses and prisms.

Available on [Hackage](https://hackage.haskell.org/package/generic-lens)

This library uses `GHC.Generics` to derive efficient optics (traversals, lenses
and prisms) for algebraic data types in a type-directed way, with a focus on
good type inference and error messages when possible.

The derived optics use the so-called van Laarhoven representation, thus are
fully interoperable with the combinators found in mainstream lens libraries.

Examples can be found in the `examples` and `tests` folders.

Table of contents
=================

* [Preliminaries](#preliminaries)
* [Taxonomy of optics](#taxonomy-of-optics)
   * [Lenses](#lenses)
      * [By name](#by-name)
      * [By position](#by-position)
      * [By type](#by-type)
      * [By structure](#by-structure)
   * [Traversals](#traversals)
      * [By type](#by-type-1)
      * [By parameter](#by-parameter)
      * [By constraint](#by-constraint)
   * [Prisms](#prisms)
      * [By name](#by-name-1)
      * [By type](#by-type-2)
* [Performance](#performance)
  * [Inspection testing](#inspection-testing)
  * [Benchmarks](#benchmarks)
* [Contributors](#contributors)

# Preliminaries
A typical module using `generic-lens` will usually have the following
extensions turned on:
```haskell
{-# LANGUAGE AllowAmbiguousTypes       #-}
{-# LANGUAGE DataKinds                 #-}
{-# LANGUAGE DeriveGeneric             #-}
{-# LANGUAGE DuplicateRecordFields     #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE TypeApplications          #-}

```

# Taxonomy of optics
Here is a comprehensive list of the optics exposed by `generic-lens`. The
combinators each allow a different way of identifying certain parts of
algebraic data types.

## Lenses

A lens identifies exactly one part of a product type, and allows querying and
updating it.

### By name

```haskell
data Person = Person { name :: String, age :: Int } deriving (Generic, Show)

sally :: Person
sally = Person "Sally" 25
```

Record fields can be accessed by their label using the `field` lens.

```haskell
>>> sally ^. field @"name"
"Sally"

>>> sally & field @"name" .~ "Tamas"
Person {name = "Tamas", age = 25}
```
Here we use [visible type application](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#visible-type-application)
to specify which field we're interested in, and use the `^.` and `.~` combinators from a lens library
([lens](https://hackage.haskell.org/package/lens), [microlens](https://hackage.haskell.org/package/microlens), etc.)
to query and update the field.

Or for standalone use, the `getField` and `setField` functions can be used instead.
```haskell
>>> getField @"age" sally
25

>>> setField @"age" 26 sally
Person {name = "Sally", age = 26}
```

When a non-existent field is requested, the library generates a helpful type error:
```haskell
>>> sally ^. field @"pet"
error:
  • The type Person does not contain a field named 'pet'
```

For types with multiple constructors, we can still use `field` as long as all constructors contain the required field
```haskell
data Two
 = First  { wurble :: String, banana :: Int }
 | Second { wurble :: String }
 deriving (Generic, Show)

>>> Second "woops" ^. field @"wurble"
"woops"
>>> Second "woops" ^. field @"banana"
    ...
    • Not all constructors of the type Two
       contain a field named 'banana'.
      The offending constructors are:
      • Second
    ...
```

The type of `field` is
```haskell
field :: HasField name s t a b => Lens s t a b
```
Therefore it allows polymorphic (type-changing) updates, when the accessed field mentions type parameters.

```haskell
data Foo f a = Foo
  { foo :: f a
  } deriving (Generic, Show)

foo1 :: Foo Maybe Int
foo1 = Foo (Just 10)

-- |
-- >>> foo2
-- Foo {foo = ["10"]}
foo2 :: Foo [] String
foo2 = foo1 & field @"foo" %~ (maybeToList . fmap show)
```
This example shows that higher-kinded parameters can also be changed (`Maybe`
-> `[]`). We turn a `Foo Maybe Int` into a `Foo [] String` by turning the inner
`Maybe Int` into a `[String]`.

With `DuplicateRecordFields`, multiple data types can share the same field
name, and the `field` lens works in this case too. No more field name
prefixing!

### By position

Fields can be accessed by their position in the data structure (index starting at 1):

```haskell
data Point = Point Int Int Int deriving (Generic, Show)
data Polygon = Polygon Point Point Point deriving (Generic, Show)

polygon :: Polygon
polygon = Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 7 (-2))
```

```haskell
>>> polygon ^. position @1 . position @2
5

>>> polygon & position @3 . position @2 %~ (+10)
Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 17 (-2))

>>> polygon ^. position @10
error:
  • The type Polygon does not contain a field at position 10
```

Since tuples are an instance of `Generic`, the positional lens readily works:

```haskell
>>> (("hello", True), 5) ^. position @1 . position @2
True
>>> (("hello", True, "or"), 5, "even", "longer") ^. position @1 . position @2
True
```

### By type

Fields can be accessed by their type in the data structure, assuming that this
type is unique:

```haskell
>>> sally ^. typed @String
"Sally"

>>> setTyped @Int sally 26
Person {name = "Sally", age = 26}
```

### By structure

The `super` lens generalises the `field` lens to focus on a collection rather
than a single field.
We can say that a record is a (structural) `subtype' of another, if its fields
are a superset of those of the other.

```haskell
data Human = Human
  { name    :: String
  , age     :: Int
  , address :: String
  } deriving (Generic, Show)

data Animal = Animal
  { name    :: String
  , age     :: Int
  } deriving (Generic, Show)

human :: Human
human = Human {name = "Tunyasz", age = 50, address = "London"}
```

```haskell
>>> human ^. super @Animal
Animal {name = "Tunyasz", age = 50}

>>> upcast human :: Animal
Animal {name = "Tunyasz", age = 50}
```

We can apply a function that operates on a supertype to the larger (subtype)
structure, by focusing on the supertype first:

```haskell
growUp :: Animal -> Animal
growUp (Animal name age) = Animal name (age + 50)

>>> human & super @Animal %~ growUp
Human {name = "Tunyasz", age = 60, address = "London"}
```

## Traversals

Traversals allow multiple values to be queried or updated at the same time.

As a running example, consider a data type of weighted trees. There are two
type parameters, which correspond to the type of elements and weights in the
tree:
```haskell
data WTree a w
  = Leaf a
  | Fork (WTree a w) (WTree a w)
  | WithWeight (WTree a w) w
  deriving (Generic, Show)

mytree :: WTree Int Int
mytree = Fork (WithWeight (Leaf 42) 1)
              (WithWeight (Fork (Leaf 88) (Leaf 37)) 2)
```

### By type
Focus on all values of a given type.

```haskell
types :: HasTypes s a => Traversal' s a
```

```haskell
>>> toListOf (types @Int) myTree
[42,1,88,37,2]
```

Note that this traversal is "deep": the subtrees are recursively traversed.

### By parameter
As the above example shows, the `types` traversal is limited in that it cannot
distinguish between the two types of `Int`s: the weights and the values.

Instead, the `param` traversal allows specifying types that correspond to a
certain type parameter.
```haskell
param :: HasParam pos s t a b => Traversal s t a b
```

```haskell
>>> toListOf (param @1) myTree
[42,88,37]
```

Here, the numbering starts from 0, with 0 being the rightmost parameter.
Because `param` is guaranteed to focus on parametric values, it allows the type
to be changed as well.

For example, we can implement `Functor` for `WTree` as simply as:

```haskell
instance Functor (WTree a) where
  fmap = over (param @0)
```

### By constraint
The most general type of traversal: we can apply a given function to every
value in a structure, by requiring that all values have an instance for some
type class.

```haskell
constraints   :: HasConstraints c s t => Applicative g => (forall a b . c a b => a -> g b) -> s -> g t
constraints'  :: HasConstraints' c s  => Applicative g => (forall a . c a => a -> g a) -> s -> g s
```

Consider the `Numbers` type, which contains three different numeric types:
```haskell
data Numbers = Numbers Int Float Double
  deriving (Show, Generic)

numbers = Numbers 10 20.0 30.0
```

With `constraints'`, we can uniformly add 20 to each number in one go:
```haskell
>>> constraints' @Num (\x -> pure (x + 20)) numbers
Numbers 30 40.0 50.0
```

## Prisms

A prism focuses on one part of a sum type (which might not be present). Other
than querying the type, they can be "turned around" to inject the data into the
sum (like a constructor).

### By name

Constructor components can be accessed using the constructor's name:

```haskell
type Name = String
type Age  = Int

data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
data Animal = Dog Dog | Cat Name Age | Duck Age deriving (Generic, Show)

shep = Dog (MkDog "Shep" 4)
mog = Cat "Mog" 5
donald = Duck 4
```

```haskell
>>> shep ^? _Ctor @"Dog"
Just (MkDog {name = "Shep", age = 4})

>>> shep ^? _Ctor @"Cat"
Nothing
```

Constructors with multiple fields can be focused as a tuple

```
>>> mog ^? _Ctor @"Cat"
Just ("Mog",5)

>>> _Ctor @"Cat" # ("Garfield", 6) :: Animal
Cat "Garfield" 6

```

### By type

Constructor components can be accessed using the component's type, assuming
that this type is unique:

```haskell
type Name = String
type Age  = Int

data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
data Animal = Dog Dog | Cat Name Age | Duck Age deriving (Generic, Show)

shep = Dog (MkDog "Shep" 4)
mog = Cat "Mog" 5
donald = Duck 4
```

```haskell
>>> mog ^? _Typed @Dog
Nothing

>>> shep ^? _Typed @Dog
Just (MkDog {name = "Shep", age = 4})

>>> donald ^? _Typed @Age
Just 4

>>> mog ^? _Typed @(Name, Age)
("Mog", 5)

>>> donald ^? _Typed @Float
error:
  • The type Animal does not contain a constructor whose field is of type Float

>>> _Typed @Age # 6 :: Animal
Duck 6
```

# Performance
The runtime characteristics of the derived optics is in most cases identical at
`-O1`, in some cases only slightly slower than the hand-written version. This
is thanks to GHC's optimiser eliminating the generic overhead.

The
[inspection-testing](https://hackage.haskell.org/package/inspection-testing)
library is used to ensure (see [here](test/Spec.hs)) that everything gets
inlined away.

TODO push benchmarks too
# Contributors

+ [Matthew Pickering](https://github.com/mpickering)
+ [Toby Shaw](https://github.com/TobyShaw)
+ [Will Jones](https://github.com/lunaris)