lens-4.19.2: Lenses, Folds and Traversals
Copyright(C) 2012-16 Edward Kmett
LicenseBSD-style (see the file LICENSE)
MaintainerEdward Kmett <ekmett@gmail.com>
Stabilityprovisional
Portabilitynon-portable
Safe HaskellTrustworthy
LanguageHaskell2010

Control.Lens.Prism

Description

 
Synopsis

Prisms

type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t) #

A Prism l is a Traversal that can also be turned around with re to obtain a Getter in the opposite direction.

There are three 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:

preview l (review l b) ≡ Just b

Second, if you can extract a value a using a Prism l from a value s, then the value s is completely described by l and a:

preview l s ≡ Just a ⟹ review l a ≡ s

Third, if you get non-match t, you can convert it result back to s:

matching l s ≡ Left t ⟹ matching l t ≡ Left s

The first two laws imply that the Traversal laws hold for every Prism and that we traverse at most 1 element:

lengthOf l x <= 1

It may help to think of this as an Iso that can be partial in one direction.

Every Prism is a valid Traversal.

Every Iso is a valid Prism.

For example, you might have a Prism' Integer Natural allows you to always go from a Natural 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' Integer Natural
nat = prism toInteger $ \ i ->
   if i < 0
   then Left i
   else Right (fromInteger i)

Now we can ask if an Integer is a Natural.

>>> 5^?nat
Just 5
>>> (-5)^?nat
Nothing

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 -- :: Natural
5

Similarly we can use a Prism to traverse the Left half of an Either:

>>> Left "hello" & _Left %~ length
Left 5

or to construct an Either:

>>> 5^.re _Left
Left 5

such that if you query it with the Prism, you will get your original input back.

>>> 5^.re _Left ^? _Left
Just 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 Prism' s a = Prism s s a a #

type APrism s t a b = Market a b a (Identity b) -> Market a b s (Identity t) #

If you see this in a signature for a function, the function is expecting a Prism.

type APrism' s a = APrism s s a a #

type APrism' = Simple APrism

Constructing Prisms

prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b #

Build a Prism.

Either t a is used instead of Maybe a to permit the types of s and t to differ.

prism' :: (b -> s) -> (s -> Maybe a) -> Prism s s a b #

This is usually used to build a Prism', when you have to use an operation like cast which already returns a Maybe.

Consuming Prisms

withPrism :: APrism s t a b -> ((b -> t) -> (s -> Either t a) -> r) -> r #

Convert APrism to the pair of functions that characterize it.

clonePrism :: APrism s t a b -> Prism s t a b #

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.

outside :: Representable p => APrism s t a b -> Lens (p t r) (p s r) (p b r) (p a r) #

Use a Prism as a kind of first-class pattern.

outside :: Prism 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) #

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) #

Given a pair of prisms, project sums.

Viewing a Prism as a co-Lens, this combinator can be seen to be dual to alongside.

below :: Traversable f => APrism' s a -> Prism' (f s) (f a) #

lift a Prism through a Traversable functor, giving a Prism that matches only if all the elements of the container match the Prism.

>>> [Left 1, Right "foo", Left 4, Right "woot"]^..below _Right
[]
>>> [Right "hail hydra!", Right "foo", Right "blah", Right "woot"]^..below _Right
[["hail hydra!","foo","blah","woot"]]

isn't :: APrism s t a b -> s -> Bool #

Check to see if this Prism doesn't match.

>>> isn't _Left (Right 12)
True
>>> isn't _Left (Left 12)
False
>>> isn't _Empty []
False
isn't = not . is
isn't = hasn't

matching :: APrism s t a b -> s -> Either t a #

Retrieve the value targeted by a Prism or return the original value while allowing the type to change if it does not match.

>>> matching _Just (Just 12)
Right 12
>>> matching _Just (Nothing :: Maybe Int) :: Either (Maybe Bool) Int
Left Nothing

Common Prisms

_Left :: Prism (Either a c) (Either b c) a b #

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 # 5
Left 5
>>> 5^.re _Left
Left 5

_Right :: Prism (Either c a) (Either c b) a b #

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 # 5
Right 5
>>> 5^.re _Right
Right 5

_Just :: Prism (Maybe a) (Maybe b) a b #

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 # 5
Just 5
>>> 5^.re _Just
Just 5

Interestingly,

m ^? _Just ≡ m
>>> Just x ^? _Just
Just x
>>> Nothing ^? _Just
Nothing

_Nothing :: Prism' (Maybe a) () #

This Prism provides the Traversal of a Nothing in a Maybe.

>>> Nothing ^? _Nothing
Just ()
>>> Just () ^? _Nothing
Nothing

But you can turn it around and use it to construct Nothing as well:

>>> _Nothing # ()
Nothing

_Void :: Prism s s a Void #

Void is a logically uninhabited data type.

This is a Prism that will always fail to match.

_Show :: (Read a, Show a) => Prism' String a #

This is an improper prism for text formatting based on Read and Show.

This Prism is "improper" in the sense that it normalizes the text formatting, but round tripping is idempotent given sane Read/Show instances.

>>> _Show # 2
"2"
>>> "EQ" ^? _Show :: Maybe Ordering
Just EQ
_Showprism' show readMaybe

only :: Eq a => a -> Prism' a () #

This Prism compares for exact equality with a given value.

>>> only 4 # ()
4
>>> 5 ^? only 4
Nothing

nearly :: a -> (a -> Bool) -> Prism' a () #

This Prism compares for approximate equality with a given value and a predicate for testing, an example where the value is the empty list and the predicate checks that a list is empty (same as _Empty with the AsEmpty list instance):

>>> nearly [] null # ()
[]
>>> [1,2,3,4] ^? nearly [] null
Nothing
nearly [] null :: Prism' [a] ()

To comply with the Prism laws the arguments you supply to nearly a p are somewhat constrained.

We assume p x holds iff x ≡ a. Under that assumption then this is a valid Prism.

This is useful when working with a type where you can test equality for only a subset of its values, and the prism selects such a value.

Prismatic profunctors

class Profunctor p => Choice (p :: Type -> Type -> Type) where #

The generalization of Costar of Functor that is strong with respect to Either.

Note: This is also a notion of strength, except with regards to another monoidal structure that we can choose to equip Hask with: the cocartesian coproduct.

Minimal complete definition

left' | right'

Methods

left' :: p a b -> p (Either a c) (Either b c) #

Laws:

left'dimap swapE swapE . right' where
  swapE :: Either a b -> Either b a
  swapE = either Right Left
rmap Leftlmap Left . left'
lmap (right f) . left'rmap (right f) . left'
left' . left'dimap assocE unassocE . left' where
  assocE :: Either (Either a b) c -> Either a (Either b c)
  assocE (Left (Left a)) = Left a
  assocE (Left (Right b)) = Right (Left b)
  assocE (Right c) = Right (Right c)
  unassocE :: Either a (Either b c) -> Either (Either a b) c
  unassocE (Left a) = Left (Left a)
  unassocE (Right (Left b)) = Left (Right b)
  unassocE (Right (Right c)) = Right c

right' :: p a b -> p (Either c a) (Either c b) #

Laws:

right'dimap swapE swapE . left' where
  swapE :: Either a b -> Either b a
  swapE = either Right Left
rmap Rightlmap Right . right'
lmap (left f) . right'rmap (left f) . right'
right' . right'dimap unassocE assocE . right' where
  assocE :: Either (Either a b) c -> Either a (Either b c)
  assocE (Left (Left a)) = Left a
  assocE (Left (Right b)) = Right (Left b)
  assocE (Right c) = Right (Right c)
  unassocE :: Either a (Either b c) -> Either (Either a b) c
  unassocE (Left a) = Left (Left a)
  unassocE (Right (Left b)) = Left (Right b)
  unassocE (Right (Right c)) = Right c

Instances

Instances details
Choice ReifiedFold # 
Instance details

Defined in Control.Lens.Reified

Methods

left' :: ReifiedFold a b -> ReifiedFold (Either a c) (Either b c) #

right' :: ReifiedFold a b -> ReifiedFold (Either c a) (Either c b) #

Choice ReifiedGetter # 
Instance details

Defined in Control.Lens.Reified

Methods

left' :: ReifiedGetter a b -> ReifiedGetter (Either a c) (Either b c) #

right' :: ReifiedGetter a b -> ReifiedGetter (Either c a) (Either c b) #

Monad m => Choice (Kleisli m) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Kleisli m a b -> Kleisli m (Either a c) (Either b c) #

right' :: Kleisli m a b -> Kleisli m (Either c a) (Either c b) #

Profunctor p => Choice (CofreeMapping p) 
Instance details

Defined in Data.Profunctor.Mapping

Methods

left' :: CofreeMapping p a b -> CofreeMapping p (Either a c) (Either b c) #

right' :: CofreeMapping p a b -> CofreeMapping p (Either c a) (Either c b) #

Choice (FreeMapping p) 
Instance details

Defined in Data.Profunctor.Mapping

Methods

left' :: FreeMapping p a b -> FreeMapping p (Either a c) (Either b c) #

right' :: FreeMapping p a b -> FreeMapping p (Either c a) (Either c b) #

Profunctor p => Choice (TambaraSum p) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: TambaraSum p a b -> TambaraSum p (Either a c) (Either b c) #

right' :: TambaraSum p a b -> TambaraSum p (Either c a) (Either c b) #

Choice (PastroSum p) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: PastroSum p a b -> PastroSum p (Either a c) (Either b c) #

right' :: PastroSum p a b -> PastroSum p (Either c a) (Either c b) #

Choice p => Choice (Tambara p) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Tambara p a b -> Tambara p (Either a c) (Either b c) #

right' :: Tambara p a b -> Tambara p (Either c a) (Either c b) #

Choice (Tagged :: Type -> Type -> Type) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Tagged a b -> Tagged (Either a c) (Either b c) #

right' :: Tagged a b -> Tagged (Either c a) (Either c b) #

Choice (Indexed i) # 
Instance details

Defined in Control.Lens.Internal.Indexed

Methods

left' :: Indexed i a b -> Indexed i (Either a c) (Either b c) #

right' :: Indexed i a b -> Indexed i (Either c a) (Either c b) #

Choice ((->) :: Type -> Type -> Type) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: (a -> b) -> Either a c -> Either b c #

right' :: (a -> b) -> Either c a -> Either c b #

Comonad w => Choice (Cokleisli w)

extract approximates costrength

Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Cokleisli w a b -> Cokleisli w (Either a c) (Either b c) #

right' :: Cokleisli w a b -> Cokleisli w (Either c a) (Either c b) #

Applicative f => Choice (Star f) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Star f a b -> Star f (Either a c) (Either b c) #

right' :: Star f a b -> Star f (Either c a) (Either c b) #

Monoid r => Choice (Forget r :: Type -> Type -> Type) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Forget r a b -> Forget r (Either a c) (Either b c) #

right' :: Forget r a b -> Forget r (Either c a) (Either c b) #

Choice (Market a b) # 
Instance details

Defined in Control.Lens.Internal.Prism

Methods

left' :: Market a b a0 b0 -> Market a b (Either a0 c) (Either b0 c) #

right' :: Market a b a0 b0 -> Market a b (Either c a0) (Either c b0) #

Functor f => Choice (Joker f :: Type -> Type -> Type) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Joker f a b -> Joker f (Either a c) (Either b c) #

right' :: Joker f a b -> Joker f (Either c a) (Either c b) #

ArrowChoice p => Choice (WrappedArrow p) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: WrappedArrow p a b -> WrappedArrow p (Either a c) (Either b c) #

right' :: WrappedArrow p a b -> WrappedArrow p (Either c a) (Either c b) #

(Choice p, Choice q) => Choice (Sum p q) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Sum p q a b -> Sum p q (Either a c) (Either b c) #

right' :: Sum p q a b -> Sum p q (Either c a) (Either c b) #

(Choice p, Choice q) => Choice (Product p q) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Product p q a b -> Product p q (Either a c) (Either b c) #

right' :: Product p q a b -> Product p q (Either c a) (Either c b) #

(Functor f, Choice p) => Choice (Tannen f p) 
Instance details

Defined in Data.Profunctor.Choice

Methods

left' :: Tannen f p a b -> Tannen f p (Either a c) (Either b c) #

right' :: Tannen f p a b -> Tannen f p (Either c a) (Either c b) #

(Functor f, Choice p) => Choice (Cayley f p) 
Instance details

Defined in Data.Profunctor.Cayley

Methods

left' :: Cayley f p a b -> Cayley f p (Either a c) (Either b c) #

right' :: Cayley f p a b -> Cayley f p (Either c a) (Either c b) #

(Choice p, Choice q) => Choice (Procompose p q) 
Instance details

Defined in Data.Profunctor.Composition

Methods

left' :: Procompose p q a b -> Procompose p q (Either a c) (Either b c) #

right' :: Procompose p q a b -> Procompose p q (Either c a) (Either c b) #