Safe Haskell | None |
---|---|

Language | Haskell2010 |

An `Iso`

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

## Synopsis

- type Iso s t a b = Optic An_Iso NoIx s t a b
- type Iso' s a = Optic' An_Iso NoIx s a
- iso :: (s -> a) -> (b -> t) -> Iso s t a b
- equality :: (s ~ a, t ~ b) => Iso s t a b
- simple :: Iso' a a
- coerced :: (Coercible s a, Coercible t b) => Iso s t a b
- coercedTo :: forall a s. Coercible s a => Iso' s a
- coerced1 :: forall f s a. (Coercible s (f s), Coercible a (f a)) => Iso (f s) (f a) s a
- non :: Eq a => a -> Iso' (Maybe a) a
- non' :: Prism' a () -> Iso' (Maybe a) a
- anon :: a -> (a -> Bool) -> Iso' (Maybe a) a
- curried :: Iso ((a, b) -> c) ((d, e) -> f) (a -> b -> c) (d -> e -> f)
- uncurried :: Iso (a -> b -> c) (d -> e -> f) ((a, b) -> c) ((d, e) -> f)
- flipped :: Iso (a -> b -> c) (a' -> b' -> c') (b -> a -> c) (b' -> a' -> c')
- involuted :: (a -> a) -> Iso' a a
- class Bifunctor p => Swapped p where
- withIso :: Iso s t a b -> ((s -> a) -> (b -> t) -> r) -> r
- au :: Functor f => Iso s t a b -> ((b -> t) -> f s) -> f a
- under :: Iso s t a b -> (t -> s) -> b -> a
- mapping :: (Functor f, Functor g) => Iso s t a b -> Iso (f s) (g t) (f a) (g b)
- data An_Iso :: OpticKind

# Formation

# 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

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

`>>>`

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

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

Data types that are representationally equal are isomorphic.

`>>>`

Identity 'x'`view coerced 'x' :: Identity Char`

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`

`>>>`

MkInt 6`over (coercedTo @Int) (*3) (MkInt 2)`

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.

`>>>`

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

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

is an isomorphism from `non`

v

to `Maybe`

a'`a`

.

`non`

≡`non'`

`.`

`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.

`>>>`

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

`>>>`

fromList []`Map.fromList [("hello",1)] & at "hello" % non 0 %~ (subtract 1)`

`>>>`

1`Map.fromList [("hello",1)] ^. at "hello" % non 0`

`>>>`

0`Map.fromList [] ^. at "hello" % non 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:

`>>>`

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

and when have deleting the last entry from the nested `Map`

mean
that we should delete its entry from the surrounding one:

`>>>`

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

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

`>>>`

Just 2`non 0 # rem 10 4`

`>>>`

Nothing`non 0 # rem 10 5`

*Since: 0.2*

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

generalizes `non'`

p

to take any unit `non`

(p # ())`Prism`

This function generates an isomorphism between

and `Maybe`

(a | `isn't`

p a)`a`

.

`>>>`

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

`>>>`

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

*Since: 0.2*

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

generalizes `anon`

a p

to take any value and a predicate.`non`

a

`anon`

a ≡`non'`

`.`

`nearly`

a

This function assumes that `p a`

holds

and generates an isomorphism
between `True`

and `Maybe`

(a | `not`

(p a))`a`

.

`>>>`

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

`>>>`

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

*Since: 0.2*

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

The isomorphism for flipping a function.

`>>>`

(2,1)`(view flipped (,)) 1 2`

# Additional elimination forms

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

Extract the two components of an isomorphism.

# Combinators

# Subtyping

data An_Iso :: OpticKind Source #

Tag for an iso.