lens-5.2.3: 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

Contents

- Prisms
- Constructing Prisms
- Consuming Prisms
- Common Prisms
- Prismatic profunctors

Description

Synopsis

- type Prism s t a b = forall (p :: Type -> Type -> Type) (f :: Type -> Type). (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 (Identity b) -> Market a b s (Identity 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
- withPrism :: APrism s t a b -> ((b -> t) -> (s -> Either t a) -> r) -> r
- clonePrism :: APrism s t a b -> Prism s t a b
- outside :: forall (p :: Type -> Type -> Type) s t a b r. Representable p => APrism s t a b -> Lens (p t r) (p s r) (p b r) (p 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)
- below :: forall (f :: Type -> Type) s a. Traversable f => APrism' s a -> Prism' (f s) (f a)
- isn't :: APrism s t a b -> s -> Bool
- matching :: APrism s t a b -> s -> Either t a
- matching' :: LensLike (Either a) s t a b -> s -> Either t a
- _Left :: forall a c b p f. (Choice p, Applicative f) => p a (f b) -> p (Either a c) (f (Either b c))
- _Right :: forall c a b p f. (Choice p, Applicative f) => p a (f b) -> p (Either c a) (f (Either c b))
- _Just :: forall a b p f. (Choice p, Applicative f) => p a (f b) -> p (Maybe a) (f (Maybe b))
- _Nothing :: forall a p f. (Choice p, Applicative f) => p () (f ()) -> p (Maybe a) (f (Maybe a))
- _Void :: forall s a p f. (Choice p, Applicative f) => p a (f Void) -> p s (f s)
- _Show :: (Read a, Show a) => Prism' String a
- only :: Eq a => a -> Prism' a ()
- nearly :: a -> (a -> Bool) -> Prism' a ()
- class Prefixed t where
  - prefixed :: t -> Prism' t t
- class Suffixed t where
  - suffixed :: t -> Prism' t t
- class Profunctor p => Choice (p :: Type -> Type -> Type) where
  - left' :: p a b -> p (Either a c) (Either b c)
  - right' :: p a b -> p (Either c a) (Either c b)

# Prisms

type Prism s t a b = forall (p :: Type -> Type -> Type) (f :: Type -> Type). (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 #

A `Simple` `Prism`.

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 :: forall (p :: Type -> Type -> Type) s t a b r. 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 :: forall (f :: Type -> Type) s a. 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

matching' :: LensLike (Either a) s t a b -> s -> Either t a #

Like `matching`, but also works for combinations of `Lens` and `Prism`s, and also `Traversal`s.

    >>> matching' (_2 . _Just) ('x', Just True)
    Right True

    >>> matching' (_2 . _Just) ('x', Nothing :: Maybe Int) :: Either (Char, Maybe Bool) Int
    Left ('x',Nothing)

    >>> matching' traverse "" :: Either [Int] Char
    Left []

    >>> matching' traverse "xyz" :: Either [Int] Char
    Right 'x'

# Common Prisms

_Left :: forall a c b p f. (Choice p, Applicative f) => p a (f b) -> p (Either a c) (f (Either b c)) #

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 :: forall c a b p f. (Choice p, Applicative f) => p a (f b) -> p (Either c a) (f (Either c 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 :: forall a b p f. (Choice p, Applicative f) => p a (f b) -> p (Maybe a) (f (Maybe 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 :: forall a p f. (Choice p, Applicative f) => p () (f ()) -> p (Maybe a) (f (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 :: forall s a p f. (Choice p, Applicative f) => p a (f Void) -> p s (f s) #

`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

    _Show ≡ prism' 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.

class Prefixed t where #

Methods

prefixed :: t -> Prism' t t #

A `Prism` stripping a prefix from a sequence when used as a `Traversal`, or prepending that prefix when run backwards:

    >>> "preview" ^? prefixed "pre"
    Just "view"

    >>> "review" ^? prefixed "pre"
    Nothing

    >>> prefixed "pre" # "amble"
    "preamble"

#### Instances

Instances details

Prefixed ByteString # |
Instance details Defined in Control.Lens.Prism Methods prefixed :: ByteString -> Prism' ByteString ByteString #
Prefixed ByteString # |
Instance details Defined in Control.Lens.Prism Methods prefixed :: ByteString -> Prism' ByteString ByteString #
Prefixed Text # |
Instance details Defined in Control.Lens.Prism Methods prefixed :: Text -> Prism' Text Text #
Prefixed Text # |
Instance details Defined in Control.Lens.Prism Methods prefixed :: Text -> Prism' Text Text #
Eq a => Prefixed [a] # |
Instance details Defined in Control.Lens.Prism Methods prefixed :: [a] -> Prism' [a] [a] #

class Suffixed t where #

Methods

suffixed :: t -> Prism' t t #

A `Prism` stripping a suffix from a sequence when used as a `Traversal`, or appending that suffix when run backwards:

    >>> "review" ^? suffixed "view"
    Just "re"

    >>> "review" ^? suffixed "tire"
    Nothing

    >>> suffixed ".o" # "hello"
    "hello.o"

#### Instances

Instances details

Suffixed ByteString # |
Instance details Defined in Control.Lens.Prism Methods suffixed :: ByteString -> Prism' ByteString ByteString #
Suffixed ByteString # |
Instance details Defined in Control.Lens.Prism Methods suffixed :: ByteString -> Prism' ByteString ByteString #
Suffixed Text # |
Instance details Defined in Control.Lens.Prism Methods suffixed :: Text -> Prism' Text Text #
Suffixed Text # |
Instance details Defined in Control.Lens.Prism Methods suffixed :: Text -> Prism' Text Text #
Eq a => Suffixed [a] # |
Instance details Defined in Control.Lens.Prism Methods suffixed :: [a] -> Prism' [a] [a] #

# 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 Left ≡ lmap 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 Right ≡ lmap 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) #
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 (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) #
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) #
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) #
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) #
Profunctor p => Choice (CofreeTraversing p) |
Instance details Defined in Data.Profunctor.Traversing Methods left' :: CofreeTraversing p a b -> CofreeTraversing p (Either a c) (Either b c) # right' :: CofreeTraversing p a b -> CofreeTraversing p (Either c a) (Either c b) #
Choice (FreeTraversing p) |
Instance details Defined in Data.Profunctor.Traversing Methods left' :: FreeTraversing p a b -> FreeTraversing p (Either a c) (Either b c) # right' :: FreeTraversing p a b -> FreeTraversing p (Either c a) (Either c b) #
Choice p => Choice (Coyoneda p) |
Instance details Defined in Data.Profunctor.Yoneda Methods left' :: Coyoneda p a b -> Coyoneda p (Either a c) (Either b c) # right' :: Coyoneda p a b -> Coyoneda p (Either c a) (Either c b) #
Choice p => Choice (Yoneda p) |
Instance details Defined in Data.Profunctor.Yoneda Methods left' :: Yoneda p a b -> Yoneda p (Either a c) (Either b c) # right' :: Yoneda p a b -> Yoneda 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) #
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) #
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) #
(Applicative f, Choice p) => Choice (WrappedPafb f p) # |
Instance details Defined in Control.Lens.Internal.Profunctor Methods left' :: WrappedPafb f p a b -> WrappedPafb f p (Either a c) (Either b c) # right' :: WrappedPafb f p a b -> WrappedPafb f p (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) #
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) #
Choice (->) |
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 #
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 (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) #
(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) #
(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) #