lens-5.0.1: Lenses, Folds and Traversals
Copyright (C) 2012-16 Edward Kmett
License BSD-style (see the file LICENSE)
Maintainer Edward Kmett <ekmett@gmail.com>
Stability provisional
Portability non-portable
Safe Haskell Trustworthy
Language Haskell2010

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

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 APrism s t a b = Market a b a ( Identity b) -> Market a b s ( Identity t) Source #

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

type APrism' = Simple APrism

Constructing Prisms

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

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

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

Convert APrism to the pair of functions that characterize it.

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

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

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

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

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

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

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

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

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

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

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

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

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

This Prism compares for exact equality with a given value.

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

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

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

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

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

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 Source #
Instance details

Defined in Control.Lens.Reified

Choice ReifiedGetter Source #
Instance details

Defined in Control.Lens.Reified

Monad m => Choice ( Kleisli m)
Instance details

Defined in Data.Profunctor.Choice

Profunctor p => Choice ( CofreeMapping p)
Instance details

Defined in Data.Profunctor.Mapping

Choice ( FreeMapping p)
Instance details

Defined in Data.Profunctor.Mapping

Profunctor p => Choice ( CofreeTraversing p)
Instance details

Defined in Data.Profunctor.Traversing

Choice ( FreeTraversing p)
Instance details

Defined in Data.Profunctor.Traversing

Profunctor p => Choice ( TambaraSum p)
Instance details

Defined in Data.Profunctor.Choice

Choice ( PastroSum p)
Instance details

Defined in Data.Profunctor.Choice

Choice p => Choice ( Tambara p)
Instance details

Defined in Data.Profunctor.Choice

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

Defined in Data.Profunctor.Choice

Choice ( Indexed i) Source #
Instance details

Defined in Control.Lens.Internal.Indexed

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

Defined in Data.Profunctor.Choice

Methods

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

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

Comonad w => Choice ( Cokleisli w)

extract approximates costrength

Instance details

Defined in Data.Profunctor.Choice

Applicative f => Choice ( Star f)
Instance details

Defined in Data.Profunctor.Choice

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

Defined in Data.Profunctor.Choice

Choice ( Market a b) Source #
Instance details

Defined in Control.Lens.Internal.Prism

( Applicative f, Choice p) => Choice ( WrappedPafb f p) Source #
Instance details

Defined in Control.Lens.Internal.Profunctor

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

Defined in Data.Profunctor.Choice

ArrowChoice p => Choice ( WrappedArrow p)
Instance details

Defined in Data.Profunctor.Choice

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

Defined in Data.Profunctor.Choice

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

Defined in Data.Profunctor.Choice

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

Defined in Data.Profunctor.Choice

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

Defined in Data.Profunctor.Cayley

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

Defined in Data.Profunctor.Composition