optics-core-0.3.0.1: Optics as an abstract interface: core definitions

Safe HaskellNone
LanguageHaskell2010

Optics.Iso

Contents

Description

An Isomorphism expresses the fact that two types have the same structure, and hence can be converted from one to the other in either direction.

Synopsis

Formation

type Iso s t a b = Optic An_Iso NoIx s t a b Source #

Type synonym for a type-modifying iso.

type Iso' s a = Optic' An_Iso NoIx s a Source #

Type synonym for a type-preserving iso.

Introduction

iso :: (s -> a) -> (b -> t) -> Iso s t a b Source #

Build an iso from a pair of inverse functions.

If you want to build an Iso from the van Laarhoven representation, use isoVL from the optics-vl package.

Elimination

An Iso is in particular a Getter, a Review and a Setter, therefore you can specialise types to obtain:

view   :: Iso' s a -> s -> a
review :: Iso' s a -> a -> s
over   :: Iso s t a b -> (a -> b) -> s -> t
set    :: Iso s t a b ->       b  -> s -> t

If you want to view a type-modifying Iso that is insufficiently polymorphic to be used as a type-preserving Iso', use getting:

view . getting :: Iso s t a b -> s -> a

Computation

view   (iso f g) ≡ f
review (iso f g) ≡ g

Well-formedness

The functions translating back and forth must be mutually inverse:

view i . review i ≡ id
review i . view i ≡ id

Additional introduction forms

equality :: (s ~ a, t ~ b) => Iso s t a b Source #

Capture type constraints as an isomorphism.

Note: This is the identity optic:

>>> :t view equality
view equality :: a -> a

simple :: Iso' a a Source #

Proof of reflexivity.

coerced :: (Coercible s a, Coercible t b) => Iso s t a b Source #

Data types that are representationally equal are isomorphic.

>>> view coerced 'x' :: Identity Char
Identity 'x'

coercedTo :: forall a s. Coercible s a => Iso' s a Source #

Type-preserving version of coerced with type parameters rearranged for TypeApplications.

>>> newtype MkInt = MkInt Int deriving Show
>>> over (coercedTo @Int) (*3) (MkInt 2)
MkInt 6

coerced1 :: forall f s a. (Coercible s (f s), Coercible a (f a)) => Iso (f s) (f a) s a Source #

Special case of coerced for trivial newtype wrappers.

>>> over (coerced1 @Identity) (++ "bar") (Identity "foo")
Identity "foobar"

non :: Eq a => a -> Iso' (Maybe a) a Source #

If v is an element of a type a, and a' is a sans the element v, then non v is an isomorphism from Maybe a' to a.

nonnon' . only

Keep in mind this is only a real isomorphism if you treat the domain as being Maybe (a sans v).

This is practically quite useful when you want to have a Map where all the entries should have non-zero values.

>>> Map.fromList [("hello",1)] & at "hello" % non 0 %~ (+2)
fromList [("hello",3)]
>>> Map.fromList [("hello",1)] & at "hello" % non 0 %~ (subtract 1)
fromList []
>>> Map.fromList [("hello",1)] ^. at "hello" % non 0
1
>>> Map.fromList [] ^. at "hello" % non 0
0

This combinator is also particularly useful when working with nested maps.

e.g. When you want to create the nested Map when it is missing:

>>> Map.empty & at "hello" % non Map.empty % at "world" ?~ "!!!"
fromList [("hello",fromList [("world","!!!")])]

and when have deleting the last entry from the nested Map mean that we should delete its entry from the surrounding one:

>>> Map.fromList [("hello", Map.fromList [("world","!!!")])] & at "hello" % non Map.empty % at "world" .~ Nothing
fromList []

It can also be used in reverse to exclude a given value:

>>> non 0 # rem 10 4
Just 2
>>> non 0 # rem 10 5
Nothing

Since: 0.2

non' :: Prism' a () -> Iso' (Maybe a) a Source #

non' p generalizes non (p # ()) to take any unit Prism

This function generates an isomorphism between Maybe (a | isn't p a) and a.

>>> Map.singleton "hello" Map.empty & at "hello" % non' _Empty % at "world" ?~ "!!!"
fromList [("hello",fromList [("world","!!!")])]
>>> Map.fromList [("hello", Map.fromList [("world","!!!")])] & at "hello" % non' _Empty % at "world" .~ Nothing
fromList []

Since: 0.2

anon :: a -> (a -> Bool) -> Iso' (Maybe a) a Source #

anon a p generalizes non a to take any value and a predicate.

anon a ≡ non' . nearly a

This function assumes that p a holds True and generates an isomorphism between Maybe (a | not (p a)) and a.

>>> Map.empty & at "hello" % anon Map.empty Map.null % at "world" ?~ "!!!"
fromList [("hello",fromList [("world","!!!")])]
>>> Map.fromList [("hello", Map.fromList [("world","!!!")])] & at "hello" % anon Map.empty Map.null % at "world" .~ Nothing
fromList []

Since: 0.2

curried :: Iso ((a, b) -> c) ((d, e) -> f) (a -> b -> c) (d -> e -> f) Source #

The canonical isomorphism for currying and uncurrying a function.

curried = iso curry uncurry
>>> view curried fst 3 4
3

uncurried :: Iso (a -> b -> c) (d -> e -> f) ((a, b) -> c) ((d, e) -> f) Source #

The canonical isomorphism for uncurrying and currying a function.

uncurried = iso uncurry curry
uncurried = re curried
>>> (view uncurried (+)) (1,2)
3

flipped :: Iso (a -> b -> c) (a' -> b' -> c') (b -> a -> c) (b' -> a' -> c') Source #

The isomorphism for flipping a function.

>>> (view flipped (,)) 1 2
(2,1)

involuted :: (a -> a) -> Iso' a a Source #

Given a function that is its own inverse, this gives you an Iso using it in both directions.

involutedjoin iso
>>> "live" ^. involuted reverse
"evil"
>>> "live" & involuted reverse %~ ('d':)
"lived"

class Bifunctor p => Swapped p where Source #

This class provides for symmetric bifunctors.

Methods

swapped :: Iso (p a b) (p c d) (p b a) (p d c) Source #

swapped . swappedid
first f . swapped = swapped . second f
second g . swapped = swapped . first g
bimap f g . swapped = swapped . bimap g f
>>> view swapped (1,2)
(2,1)
Instances
Swapped Either Source # 
Instance details

Defined in Optics.Iso

Methods

swapped :: Iso (Either a b) (Either c d) (Either b a) (Either d c) Source #

Swapped (,) Source # 
Instance details

Defined in Optics.Iso

Methods

swapped :: Iso (a, b) (c, d) (b, a) (d, c) Source #

Additional elimination forms

withIso :: Iso s t a b -> ((s -> a) -> (b -> t) -> r) -> r Source #

Extract the two components of an isomorphism.

au :: Functor f => Iso s t a b -> ((b -> t) -> f s) -> f a Source #

Based on ala from Conor McBride's work on Epigram.

This version is generalized to accept any Iso, not just a newtype.

>>> au (coerced1 @Sum) foldMap [1,2,3,4]
10

You may want to think of this combinator as having the following, simpler type:

au :: Iso s t a b -> ((b -> t) -> e -> s) -> e -> a

under :: Iso s t a b -> (t -> s) -> b -> a Source #

The opposite of working over a Setter is working under an isomorphism.

underover . re

Combinators

The re combinator can be used to reverse an Iso, and the mapping combinator to lift an Iso to an Iso on functorial values.

re      ::                           Iso s t a b -> Iso b a t s
mapping :: (Functor f, Functor g) => Iso s t a b -> Iso (f s) (g t) (f a) (g b)

Subtyping

data An_Iso :: OpticKind Source #

Tag for an iso.

Instances
ReversibleOptic An_Iso Source # 
Instance details

Defined in Optics.Re

Associated Types

type ReversedOptic An_Iso = (r :: Type) Source #

Methods

re :: AcceptsEmptyIndices "re" is => Optic An_Iso is s t a b -> Optic (ReversedOptic An_Iso) is b a t s Source #

Is An_Iso A_Review Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Methods

implies :: (Constraints An_Iso p -> r) -> Constraints A_Review p -> r Source #

Is An_Iso A_ReversedLens Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Is An_Iso A_Fold Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Methods

implies :: (Constraints An_Iso p -> r) -> Constraints A_Fold p -> r Source #

Is An_Iso An_AffineFold Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Is An_Iso A_Getter Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Methods

implies :: (Constraints An_Iso p -> r) -> Constraints A_Getter p -> r Source #

Is An_Iso A_ReversedPrism Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Is An_Iso A_Setter Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Methods

implies :: (Constraints An_Iso p -> r) -> Constraints A_Setter p -> r Source #

Is An_Iso A_Traversal Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Is An_Iso An_AffineTraversal Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Is An_Iso A_Prism Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Methods

implies :: (Constraints An_Iso p -> r) -> Constraints A_Prism p -> r Source #

Is An_Iso A_Lens Source # 
Instance details

Defined in Optics.Internal.Optic.Subtyping

Methods

implies :: (Constraints An_Iso p -> r) -> Constraints A_Lens p -> r Source #

Arrow arr => ArrowOptic An_Iso arr Source # 
Instance details

Defined in Optics.Arrow

Methods

overA :: Optic An_Iso is s t a b -> arr a b -> arr s t Source #

ToReadOnly An_Iso s t a b Source # 
Instance details

Defined in Optics.ReadOnly

Methods

getting :: Optic An_Iso is s t a b -> Optic' (Join A_Getter An_Iso) is s a Source #

(Functor f, Functor g) => MappingOptic An_Iso f g s t a b Source # 
Instance details

Defined in Optics.Mapping

Associated Types

type MappedOptic An_Iso :: Type Source #

Methods

mapping :: AcceptsEmptyIndices "mapping" is => Optic An_Iso is s t a b -> Optic (MappedOptic An_Iso) is (f s) (g t) (f a) (g b) Source #

type ReversedOptic An_Iso Source # 
Instance details

Defined in Optics.Re

type MappedOptic An_Iso Source # 
Instance details

Defined in Optics.Mapping