HORIZON HASKELLDocslts/ghc-10.0.x8fef28d2026-11-02Search packagesCtrl K
Theme: |

GHC 10.0.0.20260917 · lts/ghc-10.0.x · 8fef28d · 2026-11-02

Modulelens-5.3.6Haskell2010

Control.Lens.Iso

Contents
  1. Isomorphism Lenses
  2. Isomorphism Construction
  3. Consuming Isomorphisms
  4. Working with isomorphisms
  5. Common Isomorphisms
  6. Uncommon Isomorphisms
  7. Contravariant functors
  8. Profunctors
  9. Bifunctors
  10. Coercions
Synopsis
  • Packagelens-5.3.6
  • Exports45
  • LanguageHaskell2010
  • LicenceBSD-2-Clause
  • SourceType.hs

Isomorphism Lenses

typetype Iso s t a b = forall (p :: Type -> Type -> Type) (f :: Type -> Type). (Profunctor p, Functor f) => p a (f b) -> p s (f t)

Isomorphism families can be composed with another Lens using (.) and id.

Since every Iso is both a valid Lens and a valid Prism, the laws for those types imply the following laws for an Iso f:

f . from f ≡ id
from f . f ≡ id

Note: Composition with an Iso is index- and measure- preserving.

Isomorphism Construction

Consuming Isomorphisms

valuecloneIso :: AnIso s t a b -> Iso s t a b

Convert from AnIso back to any Iso.

This is useful when you need to store an isomorphism as a data type inside a container and later reconstitute it as an overloaded function.

See cloneLens or cloneTraversal for more information on why you might want to do this.

valuewithIso :: AnIso s t a b -> ((s -> a) -> (b -> t) -> r) -> r

Extract the two functions, one from s -> a and one from b -> t that characterize an Iso.

Working with isomorphisms

valueau :: Functor f => AnIso s t a b -> ((b -> t) -> f s) -> f a

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

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

Example1 expression
au (_Wrapping Sum) foldMap [1,2,3,4]10

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

au :: AnIso s t a b -> ((b -> t) -> e -> s) -> e -> a
au = xplat . from
valueauf :: (Functor f, Functor g) => AnIso s t a b -> (f t -> g s) -> f b -> g a

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

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

For a version you pass the name of the newtype constructor to, see alaf.

Example1 expression
auf (_Wrapping Sum) (foldMapOf both) Prelude.length ("hello","world")10

Mnemonically, the German auf plays a similar role to à la, and the combinator is au with an extra function argument:

auf :: Iso s t a b -> ((r -> t) -> e -> s) -> (r -> b) -> e -> a

but the signature is general.

Note: The direction of the Iso required for this function changed in lens 4.18 to match up with the behavior of au. For the old behavior use xplatf or for a version that is compatible across both old and new versions of lens you can just use coerce!

valuexplatf :: Optic (Costar f) g s t a b -> (f a -> g b) -> f s -> g t

xplatf = auf . from but with a nicer signature.

Example1 expression
xplatf (_Unwrapping Sum) (foldMapOf both) Prelude.length ("hello","world")10
xplatf :: Iso s t a b -> ((r -> a) -> e -> b) -> (r -> s) -> e -> t

Common Isomorphisms

valuesimple :: p a (f a) -> p a (f a)

Composition with this isomorphism is occasionally useful when your Lens, Control.Lens.Traversal.Traversal or Iso has a constraint on an unused argument to force that argument to agree with the type of a used argument and avoid ScopedTypeVariables or other ugliness.

valuenon :: Eq a => a -> Iso' (Maybe a) a

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.

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 Data.Map.Map where all the entries should have non-zero values.

Example1 expression
Map.fromList [("hello",1)] & at "hello" . non 0 +~ 2fromList [("hello",3)]
Example1 expression
Map.fromList [("hello",1)] & at "hello" . non 0 -~ 1fromList []
Example1 expression
Map.fromList [("hello",1)] ^. at "hello" . non 01
Example1 expression
Map.fromList [] ^. at "hello" . non 00

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

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

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

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

Example1 expression
Map.fromList [("hello",Map.fromList [("world","!!!")])] & at "hello" . non Map.empty . at "world" .~ NothingfromList []

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

Example1 expression
non 0 # rem 10 4Just 2
Example1 expression
non 0 # rem 10 5Nothing
valuenon' :: APrism' a () -> Iso' (Maybe a) a

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

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

Example1 expression
Map.singleton "hello" Map.empty & at "hello" . non' _Empty . at "world" ?~ "!!!"fromList [("hello",fromList [("world","!!!")])]
Example1 expression
Map.fromList [("hello",Map.fromList [("world","!!!")])] & at "hello" . non' _Empty . at "world" .~ NothingfromList []
valueanon :: a -> (a -> Bool) -> Iso' (Maybe a) a

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

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

Example1 expression
Map.empty & at "hello" . anon Map.empty Map.null . at "world" ?~ "!!!"fromList [("hello",fromList [("world","!!!")])]
Example1 expression
Map.fromList [("hello",Map.fromList [("world","!!!")])] & at "hello" . anon Map.empty Map.null . at "world" .~ NothingfromList []
valueenum :: Enum a => Iso' Int a

This isomorphism can be used to convert to or from an instance of Enum.

Example1 expression
LT^.from enum0
Example1 expression
97^.enum :: Char'a'

Note: this is only an isomorphism from the numeric range actually used and it is a bit of a pleasant fiction, since there are questionable Enum instances for Double, and Float that exist solely for [1.0 .. 4.0] sugar and the instances for those and Integer don't cover all values in their range.

valuecurried
  1. :: (Profunctor p, Functor f2)
  2. => p (a -> b -> c) (f2 (d -> e -> f1))
  3. -> p ((a, b) -> c) (f2 ((d, e) -> f1))

The canonical isomorphism for currying and uncurrying a function.

curried = iso curry uncurry
Example1 expression
(fst^.curried) 3 43
Example1 expression
view curried fst 3 43
valueflipped
  1. :: (Profunctor p, Functor f)
  2. => p (b -> a -> c) (f (b' -> a' -> c'))
  3. -> p (a -> b -> c) (f (a' -> b' -> c'))

The isomorphism for flipping a function.

Example1 expression
((,)^.flipped) 1 2(2,1)
classclass Reversing t where

This class provides a generalized notion of list reversal extended to other containers.

Methods

Instances13Reversing, …
valuereversed :: Reversing a => Iso' a a

An Iso between a list, ByteString, Text fragment, etc. and its reversal.

Example1 expression
"live" ^. reversed"evil"
Example1 expression
"live" & reversed %~ ('d':)"lived"
valueinvoluted :: (a -> a) -> Iso' a a

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

involuted ≡ join iso
Example1 expression
"live" ^. involuted reverse"evil"
Example1 expression
"live" & involuted reverse %~ ('d':)"lived"

Uncommon Isomorphisms

datadata Magma i t b a where

This provides a way to peek at the internal structure of a Control.Lens.Traversal.Traversal or Control.Lens.Traversal.IndexedTraversal

Instances7FoldableWithIndex, FunctorWithIndex, TraversableWithIndex, Functor, Foldable, Traversable, …

Contravariant functors

Profunctors

classclass Profunctor (p :: Type -> Type -> Type) where

Formally, the class Profunctor represents a profunctor from Hask -> Hask.

Intuitively it is a bifunctor where the first argument is contravariant and the second argument is covariant.

You can define a Profunctor by either defining dimap or by defining both lmap and rmap.

If you supply dimap, you should ensure that:

dimap id id ≡ id

If you supply lmap and rmap, ensure:

lmap id ≡ id
rmap id ≡ id

If you supply both, you should also ensure:

dimap f g ≡ lmap f . rmap g

These ensure by parametricity:

dimap (f . g) (h . i) ≡ dimap g h . dimap f i
lmap (f . g) ≡ lmap g . lmap f
rmap (f . g) ≡ rmap f . rmap g

Methods

  • dimap :: (a -> b) -> (c -> d) -> p b c -> p a d

    Map over both arguments at the same time.

    dimap f g ≡ lmap f . rmap g
  • lmap :: (a -> b) -> p b c -> p a c

    Map the first argument contravariantly.

    lmap f ≡ dimap f id
  • rmap :: (b -> c) -> p a b -> p a c

    Map the second argument covariantly.

    rmap ≡ dimap id
Instances46Profunctor, …

Bifunctors

Coercions