# purescript-lens

This started as an indirect port of @ekmett's lens library in PureScript. It has since been broken apart and simplified substantially. The core idea is that these are just van Laarhoven lenses. Read about them as they were called functional references. SPJ gave a brilliant introductory talk about them here. If you're confused, I'd recommend SPJ's talk first. @ekmett has talked about them many times, here's one. For more documentation, you should look at lens and any of the lens resources online.

## Installation

This is available on bower, so you should be able to just:

`bower i purescript-lens`

to install it.

## Usage

You *should* be able to import just `Optic.Lens`

and have most of what you need.
See each directory for a summary of the available functions.

There is no TemplateHaskell like syntax so you must define each lens individually. Or make use of purescript-refractor, which has predefined lenses and prisms.

There are two main types in this library: `Lens`

and `Prism`

.
Both propose a way for "getting" and "setting" values in a data type.
`Lens`

is for working with product types (`Tuple`

, records, fields in a data type).
`Prism`

is for working with sum types (`Maybe`

, `Either`

, etc).
Each type proposes some way to look at a specific part of a data type.

With `Lens`

, it proposes a way to look at one portion of a product type.
E.g. the first field of a tuple, or the `foo`

field of a record.

With `Prism`

, it proposes a way to look at one side of a sum type.
E.g. the `Left`

side of an `Either`

, or the `Nothing`

side of a `Maybe`

.

For almost all of the types provided there are simple versions and more general versions. Using `Lens`

as the example.

`Lens' s a`

is the simple type when you don't need to change the type of your structure.

`Lens s t a b`

is the type when you may want to change the type of your structure.

For example:

`data Foo = Bar String Number Boolean fooNum :: Lens' Foo NumberfooNum = lens (\(Bar _ n _) -> n) (\(Bar s _ b) n -> Bar s n b)`

This type and implementation states that the function `fooNum`

is a `Lens`

from the data type `Foo`

to the `Number`

field of it.
Since it is a simple type, it does not change the type of the `Number`

field or change the type of `Foo`

.

or

`foo :: forall b r a t s. Lens {foo :: a | r} {foo :: b | r} a bfoo = lens (\o -> o.foo) (\o x -> o{foo = x})`

This type and implementation states that the function `foo`

is a `Lens`

from any record with at least a `foo`

field of type `a`

to any record with at least a `foo`

field of type `b`

.

So, what are the type synonyms? Some examples are:

`type Lens s t a b = forall f. (Functor f) => (a -> f b) -> s -> f ttype Lens' s a = Lens s s a a type Prism s t a b = forall f p. (Applicative f, Choice p) => p a (f b) -> p s (f t)type Prism' s a = Prism s s a a`

These might seem scary, especially `Prism`

, but if you squint at them properly, they look very familiar.

Let's take `Lens`

, for example, and instantiate `s = [a], t = [b]`

.

Then we have some type: `forall f. (Functor f) => (a -> f b) -> [a] -> f [b]`

.

Looks pretty close to `map`

(from `Data.Array`

).
In fact, if we instantiate the `Functor`

with `Identity`

,
we get the type isomorphic to `map`

: `(a -> Identity b) -> [a] -> Identity [b]`

.

With some simple unwrapping, we actually have the type of `map`

.

What about `Prism`

?

Let's instantiate the `Choice`

to `(->)`

:
`type Prism s t a b = forall f. (Applicative f) => (a -> f b) -> s -> f t`

This looks pretty close to `traverse`

.

So, there's a bunch of similarities to the `Functor`

hierarchy, and that's one of the points of this library.
What these types synonyms allow is the ability to use similar idioms that work in the `Functor`

hierarchy on containers that are not polymorphic in one variable.

An example of this is if you have some type: `data Foo = Foo Number`

.
There's no way to define a `Functor`

instance for `Foo`

,
so you cannot use `(<$>), (<*>), (>>=), (=>>), pure, extract`

and friends.
But, it should be easy to see that it would be trivial to "map" over the `Number`

contained within a `Foo`

.

If you can define a lens for `Foo`

, you can do just that

`module Foo where import Optic.Core ((*~), Lens'()) data Foo = Foo Number _Foo :: Lens' Foo Number -- forall f. (Functor f) => (Number -> f Number) -> Foo -> f Foo _Foo f (Foo n) = Foo <$> f n doubleFoo :: Foo -> Foo doubleFoo = _Foo *~ 2`

Now, this is not necessarily the least verbose option for such a trivial example, but it is definitely one of the more general options. We were able to reuse plain old functions. If we have some deeply nested structure, it is much less verbose for that situation.

## Examples

N.B. `(..)`

is `(<<<)`

purely for aesthetic reasons.

`foo..bar..baz..quux`

looks better and reads easier than `foo<<<bar<<<baz<<<quux`

.

Using purescript-refractor for some pre-defined lenses/prisms, we can run this session.

`➜ purescript-lens git:(split) psci bower_components/purescript-*/src/**/*.purs ____ ____ _ _ | _ \ _ _ _ __ ___/ ___| ___ _ __(_)_ __ | |_ | |_) | | | | '__/ _ \___ \ / __| '__| | '_ \| __|| __/| |_| | | | __/___) | (__| | | | |_) | |_ |_| \__,_|_| \___|____/ \___|_| |_| .__/ \__| |_| :? shows help Expressions are terminated using Ctrl+D> :i Optic.Core> :i Optic.Refractor.Lens> :i Data.Tuple> (Tuple "Hello" "World")^._2 "World" > (Tuple "Hello" "World") # _2.~42 Tuple ("Hello") (42) > (Tuple "Hello" (Tuple "World" "!!!")) # _2.._1.~42 Tuple ("Hello") (Tuple (42) ("!!!"))`

## Contributing

Please do! Issues, comments, bugs, improvements, whatever.

See the guide first: contibuting.

I am not @ekmett. I don't have the drive to build this entire library by myself. Nor do I have the knowledge to do so. Any help is greatly appreciated.

If you see something wrong, don't hesitate to slap me around and explain why it's wrong.