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+
269module 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
575 , module ExportTypes
676 ) where
777
@@ -18,23 +88,75 @@ import Data.Profunctor (dimap, rmap)
1888import Data.Profunctor.Choice (right )
1989import Data.Newtype (under )
2090
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.
22104prism :: forall s t a b . (b -> t ) -> (s -> Either t a ) -> Prism s t a b
23105prism to fro pab = dimap fro (either id id) (right (rmap to pab))
24106
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+ -- | ```
25116prism' :: forall s a . (a -> s ) -> (s -> Maybe a ) -> Prism' s a
26117prism' to fro = prism to (\s -> maybe (Left s) Right (fro s))
27118
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+ -- | ```
32131nearly :: forall a . a -> (a -> Boolean ) -> Prism' a Unit
33132nearly x f = prism' (const x) (guard <<< f)
34133
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.
35148only :: forall a . Eq a => a -> Prism a a Unit Unit
36149only x = nearly x (_ == x)
37150
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+
38160clonePrism :: forall s t a b . APrism s t a b -> Prism s t a b
39161clonePrism l = withPrism l \x y p -> prism x y p
40162
@@ -45,8 +167,10 @@ withPrism l f = case l (Market id Right) of
45167matching :: forall s t a b . APrism s t a b -> s -> Either t a
46168matching l = withPrism l \_ f -> f
47169
170+ -- | Ask if `preview prism` would produce a `Just`.
48171is :: forall s t a b r . HeytingAlgebra r => APrism s t a b -> s -> r
49172is l = either (const ff) (const tt) <<< matching l
50173
174+ -- | Ask if `preview prism` would produce a `Nothing`.
51175isn't :: forall s t a b r . HeytingAlgebra r => APrism s t a b -> s -> r
52176isn't l = not <<< is l
0 commit comments