| Portability | non-portable |
|---|---|
| Stability | provisional |
| Maintainer | Edward Kmett <ekmett@gmail.com> |
| Safe Haskell | Trustworthy |
Control.Lens.Prism
Description
- type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
- type Prism' s a = Prism s s a a
- type APrism s t a b = Market a b a (Mutator b) -> Market a b s (Mutator t)
- type APrism' s a = APrism s s a a
- prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
- prism' :: (b -> s) -> (s -> Maybe a) -> Prism s s a b
- clonePrism :: APrism s t a b -> Prism s t a b
- outside :: APrism s t a b -> Lens (t -> r) (s -> r) (b -> r) (a -> r)
- aside :: APrism s t a b -> Prism (e, s) (e, t) (e, a) (e, b)
- without :: APrism s t a b -> APrism u v c d -> Prism (Either s u) (Either t v) (Either a c) (Either b d)
- isn't :: APrism s t a b -> s -> Bool
- _Left :: Prism (Either a c) (Either b c) a b
- _Right :: Prism (Either c a) (Either c b) a b
- _Just :: Prism (Maybe a) (Maybe b) a b
- _Nothing :: Prism' (Maybe a) ()
- _Void :: Prism s s a Void
- only :: Eq a => a -> Prism' a ()
- class Profunctor p => Choice p where
Prisms
type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)Source
A Prism l is a 0-or-1 target Traversal that can also be turned
around with re to obtain a Getter in the
opposite direction.
There are two laws that a Prism should satisfy:
First, if I re or review a value with a Prism and then preview or use (^?), I will get it back:
previewl (reviewl b) ≡Justb
Second, if you can extract a value a using a Prism l from a value s, then the value s is completely described my l and a:
If then preview l s ≡ Just areview l a ≡ s
These two laws imply that the Traversal laws hold for every Prism and that we traverse at most 1 element:
lengthOfl x<=1
It may help to think of this as a Iso that can be partial in one direction.
Every Prism is a valid Traversal.
For example, you might have a allows you to always
go from a Prism' Integer NaturalNatural to an Integer, and provide you with tools to check if an Integer is
a Natural and/or to edit one if it is.
nat::Prism'IntegerNaturalnat=prismtoInteger$\ i -> if i<0 thenLefti elseRight(fromIntegeri)
Now we can ask if an Integer is a Natural.
>>>5^?natJust 5
>>>(-5)^?natNothing
We can update the ones that are:
>>>(-3,4) & both.nat *~ 2(-3,8)
And we can then convert from a Natural to an Integer.
>>>5 ^. re nat -- :: Natural5
Similarly we can use a Prism to traverse the Left half of an Either:
>>>Left "hello" & _Left %~ lengthLeft 5
or to construct an Either:
>>>5^.re _LeftLeft 5
such that if you query it with the Prism, you will get your original input back.
>>>5^.re _Left ^? _LeftJust 5
Another interesting way to think of a Prism is as the categorical dual of a Lens
-- a co-Lens, so to speak. This is what permits the construction of outside.
Note: Composition with a Prism is index-preserving.
type APrism s t a b = Market a b a (Mutator b) -> Market a b s (Mutator t)Source
If you see this in a signature for a function, the function is expecting a Prism.
Constructing Prisms
Consuming Prisms
clonePrism :: APrism s t a b -> Prism s t a bSource
Clone a Prism so that you can reuse the same monomorphically typed Prism for different purposes.
See cloneLens and cloneTraversal for examples of why you might want to do this.
aside :: APrism s t a b -> Prism (e, s) (e, t) (e, a) (e, b)Source
Use a Prism to work over part of a structure.
without :: APrism s t a b -> APrism u v c d -> Prism (Either s u) (Either t v) (Either a c) (Either b d)Source
isn't :: APrism s t a b -> s -> BoolSource
Check to see if this Prism doesn't match.
>>>isn't _Left (Right 12)True
>>>isn't _Left (Left 12)False
Common Prisms
_Left :: Prism (Either a c) (Either b c) a bSource
This Prism provides a Traversal for tweaking the Left half of an Either:
>>>over _Left (+1) (Left 2)Left 3
>>>over _Left (+1) (Right 2)Right 2
>>>Right 42 ^._Left :: String""
>>>Left "hello" ^._Left"hello"
It also can be turned around to obtain the embedding into the Left half of an Either:
>>>_Left # 5Left 5
>>>5^.re _LeftLeft 5
_Right :: Prism (Either c a) (Either c b) a bSource
This Prism provides a Traversal for tweaking the Right half of an Either:
>>>over _Right (+1) (Left 2)Left 2
>>>over _Right (+1) (Right 2)Right 3
>>>Right "hello" ^._Right"hello"
>>>Left "hello" ^._Right :: [Double][]
It also can be turned around to obtain the embedding into the Right half of an Either:
>>>_Right # 5Right 5
>>>5^.re _RightRight 5
_Just :: Prism (Maybe a) (Maybe b) a bSource
This Prism provides a Traversal for tweaking the target of the value of Just in a Maybe.
>>>over _Just (+1) (Just 2)Just 3
Unlike traverse this is a Prism, and so you can use it to inject as well:
>>>_Just # 5Just 5
>>>5^.re _JustJust 5
Interestingly,
m^?_Just≡ m
>>>Just x ^? _JustJust x
>>>Nothing ^? _JustNothing
only :: Eq a => a -> Prism' a ()Source
This Prism compares for exact equality with a given value.
>>>only 4 # ()4
>>>5 ^? only 4Nothing
Prismatic profunctors
class Profunctor p => Choice p where
The generalization of DownStar of a "costrong" Functor
Minimal complete definition: left' or right'
Note: We use traverse and extract as approximate costrength as needed.
Instances
| Choice (->) | |
| Choice Reviewed | |
| Monad m => Choice (Kleisli m) | |
| Comonad w => Choice (Cokleisli w) |
|
| Applicative f => Choice (UpStar f) | |
| Traversable w => Choice (DownStar w) |
|
| ArrowChoice p => Choice (WrappedArrow p) | |
| Monoid r => Choice (Forget r) | |
| Choice (Tagged *) | |
| Choice (Indexed i) | |
| Choice (Market a b) |