1
- -- | This module defines functions for working with prisms.
1
+ -- | Prisms are used for selecting cases of a type, most often a sum
2
+ -- | type. Consider this:
3
+ -- |
4
+ -- | ```purescript
5
+ -- | data Fill -- think of a paint program filling a shape
6
+ -- | = NoFill
7
+ -- | | Solid Color
8
+ -- | | ...
9
+ -- | ```
10
+ -- |
11
+ -- | A prism that focuses on `Solid` fills could be written like this:
12
+ -- |
13
+ -- | ```purescript
14
+ -- | solidFocus :: Prism' Fill Color
15
+ -- | solidFocus = prism' Solid case _ of
16
+ -- | Solid color -> Just color
17
+ -- | _ -> Nothing
18
+ -- | ```
19
+ -- |
20
+ -- | ... and used like this:
21
+ -- |
22
+ -- | ```purescript
23
+ -- | preview solidFocus (Solid Color.white) == Just Color.white
24
+ -- | preview solidFocus NoFill == Nothing
25
+ -- |
26
+ -- | is solidFocus (Solid Color.white) == true
27
+ -- | ```
28
+ -- |
29
+ -- | `review` can be used to go from a `Color` to a `Fill`:
30
+ -- |
31
+ -- | ```purescript
32
+ -- | review solidFocus Color.white == Solid Color.white
33
+ -- | ```
34
+ -- |
35
+ -- | For more information, see `PrismsForSumTypes.purs` in the
36
+ -- | `examples/src` directory.
37
+ -- |
38
+ -- | ---------------
39
+ -- |
40
+ -- | A well-behaved `Prism` will follow these laws:
41
+ -- |
42
+ -- | **review-preview**: `preview` retrieves what `review` creates. Equationally:
43
+ -- |
44
+ -- | ```purescript
45
+ -- | review prism >>> preview prism ≡ Just
46
+ -- | ```
47
+ -- |
48
+ -- | An example:
49
+ -- |
50
+ -- | ```purescript
51
+ -- | Color.white # review solidFocus # preview solidFocus
52
+ -- | == Just Color.white
53
+ -- | ```
54
+ -- |
55
+ -- | **preview-review**: If `preview` retrieves something, `review` can create
56
+ -- | the original from that something. Equationally:
57
+ -- |
58
+ -- | ```purescript
59
+ -- | if preview prism s ≡ Just a then review prism a ≡ s
60
+ -- | ```
61
+ -- |
62
+ -- | An example:
63
+ -- |
64
+ -- | ```purescript
65
+ -- | Solid Color.white # preview solidFocus <#> review solidFocus
66
+ -- | == Solid Color.white
67
+ -- | ```
68
+
2
69
module Data.Lens.Prism
3
- ( prism , prism' , review , nearly , only , clonePrism , withPrism , matching
4
- , is , isn't
70
+ ( prism' , prism
71
+ , only , nearly
72
+ , review
73
+ , is , isn't , matching
74
+ , clonePrism , withPrism
5
75
, module ExportTypes
6
76
) where
7
77
@@ -18,23 +88,75 @@ import Data.Profunctor (dimap, rmap)
18
88
import Data.Profunctor.Choice (right )
19
89
import Data.Newtype (under )
20
90
21
- -- | Create a `Prism` from a constructor/pattern pair.
91
+ -- | Create a `Prism` from a constructor and a matcher function that
92
+ -- | produces an `Either`:
93
+ -- |
94
+ -- | ```purescript
95
+ -- | solidFocus :: Prism' Fill Color
96
+ -- | solidFocus = prism Solid case _ of
97
+ -- | Solid color -> Right color
98
+ -- | anotherCase -> Left anotherCase
99
+ -- | ```
100
+ -- |
101
+ -- | _Note_: The matcher function returns a result wrapped in `Either t`
102
+ -- | to allow for type-changing prisms in the case where the input does
103
+ -- | not match.
22
104
prism :: forall s t a b . (b -> t ) -> (s -> Either t a ) -> Prism s t a b
23
105
prism to fro pab = dimap fro (either id id) (right (rmap to pab))
24
106
107
+ -- | Create a `Prism` from a constructor and a matcher function that
108
+ -- | produces a `Maybe`:
109
+ -- |
110
+ -- | ```purescript
111
+ -- | solidFocus :: Prism' Fill Color
112
+ -- | solidFocus = prism' Solid case _ of
113
+ -- | Solid color -> Just color
114
+ -- | _ -> Nothing
115
+ -- | ```
25
116
prism' :: forall s a . (a -> s ) -> (s -> Maybe a ) -> Prism' s a
26
117
prism' to fro = prism to (\s -> maybe (Left s) Right (fro s))
27
118
28
- -- | Review a value through a `Prism`.
29
- review :: forall s t a b . Review s t a b -> b -> t
30
- review = under Tagged
31
-
119
+ -- | `nearly` is a variant of `only`. Like `only`, `nearly` produces
120
+ -- | a prism that matches
121
+ -- | a single value. Unlike `only`, it uses a predicate you supply
122
+ -- | instead of depending on `class Eq`:
123
+ -- |
124
+ -- | ```purescript
125
+ -- | solidWhiteFocus :: Prism' Fill Unit
126
+ -- | solidWhiteFocus = nearly (Solid Color.white) predicate
127
+ -- | where
128
+ -- | predicate candidate =
129
+ -- | color.toHexString == Color.white.toHexString
130
+ -- | ```
32
131
nearly :: forall a . a -> (a -> Boolean ) -> Prism' a Unit
33
132
nearly x f = prism' (const x) (guard <<< f)
34
133
134
+ -- | `only` focuses not just on a case, but a specific value of that case.
135
+ -- |
136
+ -- | ```purescript
137
+ -- | solidWhiteFocus :: Prism' Fill Unit
138
+ -- | solidWhiteFocus = only $ Solid Color.white
139
+ -- |
140
+ -- | is solidWhiteFocus (Solid Color.white) == true
141
+ -- | preview solidWhiteFocus (Solid Color.white) == Just unit
142
+ -- | review solidWhiteFocus unit == Solid Color.white
143
+ -- | ```
144
+ -- |
145
+ -- | *Note*: `only` depends on `Eq`. Strange definitions of `(==)`
146
+ -- | (for example, that it counts any `Fill` as being equal to `Solid Color.white`)
147
+ -- | will create a prism that violates the preview-review law.
35
148
only :: forall a . Eq a => a -> Prism a a Unit Unit
36
149
only x = nearly x (_ == x)
37
150
151
+
152
+ -- | Create the "whole" corresponding to a specific "part":
153
+ -- |
154
+ -- | ```purescript
155
+ -- | review solidFocus Color.white == Solid Color.white
156
+ -- | ```
157
+ review :: forall s t a b . Review s t a b -> b -> t
158
+ review = under Tagged
159
+
38
160
clonePrism :: forall s t a b . APrism s t a b -> Prism s t a b
39
161
clonePrism l = withPrism l \x y p -> prism x y p
40
162
@@ -45,8 +167,10 @@ withPrism l f = case l (Market id Right) of
45
167
matching :: forall s t a b . APrism s t a b -> s -> Either t a
46
168
matching l = withPrism l \_ f -> f
47
169
170
+ -- | Ask if `preview prism` would produce a `Just`.
48
171
is :: forall s t a b r . HeytingAlgebra r => APrism s t a b -> s -> r
49
172
is l = either (const ff) (const tt) <<< matching l
50
173
174
+ -- | Ask if `preview prism` would produce a `Nothing`.
51
175
isn't :: forall s t a b r . HeytingAlgebra r => APrism s t a b -> s -> r
52
176
isn't l = not <<< is l
0 commit comments