You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Oct 4, 2020. It is now read-only.
What this means for you is that you have to annotate your lens/prism/traversal/whatever with a type.
37
37
This might sound or look hairy, but the types aren't that hard to figure out and it'll go quite a way to show you that there's no magic going on in this library.
38
-
They're almost all just type synonyms actually.
38
+
They're all just type synonyms actually.
39
+
40
+
----------
41
+
42
+
There are two main types in this library: `Lens` and `Prism`.
43
+
Both propose a way for "getting" and "setting" values in a data type.
44
+
`Lens` is for working with product types (`Tuple`, records, fields in a data type).
45
+
`Prism` is for working with sum types (`Maybe`, `Either`, etc).
46
+
Each type proposes some way to look at a specific part of a data type.
47
+
48
+
With `Lens`, it proposes a way to look at one portion of a product type.
49
+
E.g. the first field of a tuple, or the `foo` field of a record.
39
50
40
-
One way to think of the `Lens` type is to think of it as saying you want a lens from some structure to a piece of that structure.
51
+
With `Prism`, it proposes a way to look at one side of a sum type.
52
+
E.g. the `Left` side of an `Either`, or the `Nothing` side of a `Maybe`.
53
+
54
+
For almost all of the types provided there are simple versions and more general versions. Using `Lens` as the example.
41
55
42
56
`LensP s a` is the simple type when you don't need to change the type of your structure.
43
57
44
-
`Lens s t a b` is the type when you need to change the type of your structure,
58
+
`Lens s t a b` is the type when you may want to change the type of your structure.
45
59
46
60
For example:
47
61
48
-
```haskell
62
+
```purescript
49
63
data Foo = Bar String Number Boolean
50
64
51
65
fooNum :: LensP Foo Number
52
66
fooNum = lens (\(Bar _ n _) -> n) (\(Bar s _ b) n -> Bar s n b)
53
67
```
54
68
69
+
This type and implementation states that the function `fooNum` is a `Lens` from the data type `Foo` to the `Number` field of it.
70
+
Since it is a simple type, it does not change the type of the `Number` field or change the type of `Foo`.
71
+
55
72
or
56
73
57
-
```haskell
58
-
_foo::forallbrats.Lens {foo::a|r} {foo::b|r} ab
59
-
_foo= lens (\o -> o.foo) (\o x -> o{foo = x})
74
+
```purescript
75
+
foo :: forall b r a t s. Lens {foo :: a | r} {foo :: b | r} a b
76
+
foo = lens (\o -> o.foo) (\o x -> o{foo = x})
60
77
```
61
78
62
-
## Examples
79
+
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`.
63
80
64
-
N.B.
65
-
`(~)` is an infix version of `Tuple`.
81
+
So, what are the type synonyms? Some examples are:
66
82
67
-
It's available in `Control.Lens.Tuple`,
68
-
so it should come when you import `Control.Lens`.
69
-
It's right associative so beware of what structure it will create.
83
+
```purescript
84
+
type Lens s t a b = forall f. (Functor f) => (a -> f b) -> s -> f t
85
+
type LensP s a = Lens s s a a
70
86
71
-
`(..)` is `(<<<)` purely for aesthetic reasons.
87
+
type Prism s t a b = forall f p. (Applicative f, Choice p) => p a (f b) -> p s (f t)
88
+
type PrismP s a = Prism s s a a
89
+
```
72
90
73
-
`foo..bar..baz..quux` looks better and reads easier than `foo<<<bar<<<baz<<<quux`.
91
+
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]`.
83
94
84
-
:?shows help
95
+
Then we have some type: `forall f. (Functor f) => (a -> f b) -> [a] -> f [b]`.
85
96
86
-
Expressions are terminated using Ctrl+D
87
-
>:i Control.Lens
88
-
> ("hello"~"world")^._2
89
-
90
-
...if it's the first compile, lens imports most of the universe here...
97
+
Looks pretty close to `map` (from `Data.Array`).
98
+
In fact, if we instantiate the `Functor` with `Identity`,
99
+
we get the type isomorphic to `map`: `(a -> Identity b) -> [a] -> Identity [b]`.
91
100
92
-
"world"
101
+
With some simple unwrapping, we actually have the type of `map`.
93
102
94
-
> set _2 42 ("hello"~"world")
95
-
96
-
Tuple ("hello") (42)
103
+
What about `Prism`?
97
104
98
-
> ("hello"~ ("world"~"!!!"))^._2.._1
99
-
100
-
"world"
105
+
Let's instantiate the `Choice` to `(->)`:
106
+
`type Prism s t a b = forall f. (Applicative f) => (a -> f b) -> s -> f t`
107
+
This looks pretty close to `traverse`.
101
108
102
-
> set (_2.._1) 42 ("hello"~"world"~"!!!")
103
-
104
-
Tuple ("hello") (Tuple (42) ("!!!"))
109
+
So, there's a bunch of similarities to the `Functor` hierarchy, and that's one of the points of this library.
110
+
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.
111
+
112
+
An example of this is if you have some type: `data Foo = Foo Number`.
113
+
There's no way to define a `Functor` instance for `Foo`,
114
+
so you cannot use `(<$>), (<*>), (>>=), (=>>), pure, extract` and friends.
115
+
But, it should be easy to see that it would be trivial to "map" over the `Number` contained within a `Foo`.
116
+
117
+
If you can define a lens for `Foo`, you can do just that
118
+
119
+
```purescript
120
+
module Foo where
121
+
122
+
import Optic.Core ((*~), LensP())
123
+
124
+
data Foo = Foo Number
125
+
126
+
_Foo :: LensP Foo Number -- forall f. (Functor f) => (Number -> f Number) -> Foo -> f Foo
127
+
_Foo f (Foo n) = Foo <$> f n
128
+
129
+
doubleFoo :: Foo -> Foo
130
+
doubleFoo = _Foo *~ 2
105
131
```
106
132
107
-
Or, when using records.
133
+
Now, this is not necessarily the least verbose option for such a trivial example,
134
+
but it is definitely one of the more general options.
135
+
We were able to reuse plain old functions.
136
+
If we have some deeply nested structure, it is much less verbose for that situation.
108
137
109
-
N.B. There's no show instance for records, so we just check the type instead.
0 commit comments