HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Moduleoptics-core-0.4.1.1Haskell2010

Optics.Optic

This module provides core definitions:

  • an opaque Optic type, which is parameterised over a type representing an optic kind (instantiated with tag types such as A_Lens);

  • the optic composition operator (%);

  • the subtyping relation Is with an accompanying castOptic function to convert an optic kind;

  • the JoinKinds class used to find the optic kind resulting from a composition.

Each optic kind is identified by a "tag type" (such as A_Lens), which is an empty data type. The type of the actual optics (such as Lens) is obtained by applying Optic to the tag type.

See the Optics module in the main optics package for overview documentation.

  • 6 types
  • 7 classes
  • 6 values
newtypenewtype Optic (k :: OpticKind) (is :: IxList) s t a b
#

Wrapper newtype for the whole family of optics.

The first parameter k identifies the particular optic kind (e.g. A_Lens or A_Traversal).

The parameter is is a list of types available as indices. This will typically be NoIx for unindexed optics, or WithIx for optics with a single index. See the "Indexed optics" section of the overview documentation in the Optics module of the main optics package for more details.

The parameters s and t represent the "big" structure, whereas a and b represent the "small" structure.

Instances1IsLabel
typetype Optic' (k :: OpticKind) (is :: IxList) s a = Optic k is s s a a
#

Common special case of Optic where source and target types are equal.

Here, we need only one "big" and one "small" type. For lenses, this means that in the restricted form we cannot do type-changing updates.

Subtyping

3 declarations
valuecastOptic
  1. :: Is srcKind destKind
  2. => Optic srcKind is s t a b
  3. -> Optic destKind is s t a b
#

Explicit cast from one optic flavour to another.

The resulting optic kind is given in the first type argument, so you can use TypeApplications to set it. For example

 castOptic @A_Lens o

turns o into a Lens.

This is the identity function, modulo some constraint jiggery-pokery.

classclass Is (k :: OpticKind) (l :: OpticKind) where
#

Subtyping relationship between kinds of optics.

An instance of Is k l means that any Optic k can be used as an Optic l. For example, we have an Is A_Lens A_Traversal instance, but not Is A_Traversal A_Lens.

This class needs instances for all possible combinations of tags.

Instances38Is, …
classclass JoinKinds (k :: OpticKind) (l :: OpticKind) (m :: OpticKind) | k l -> m where
#

Computes the least upper bound of two optics kinds.

In presence of a JoinKinds k l m constraint Optic m represents the least upper bound of an Optic k and an Optic l. This means in particular that composition of an Optic k and an Optic k will yield an Optic m.

Instances105JoinKinds, …

Composition

3 declarations

The usual operator for composing optics is (%), which allows different optic kinds to be composed, automatically calculating the resulting optic kind using JoinKinds.

The (.) function composition operator cannot be used to compose optics, because optics are not functions. The (.) operator from Control.Category cannot be used either, because it would not support type-changing optics or composing optics of different kinds.

value(%)
  1. :: (JoinKinds k l m, AppendIndices is js ks)
  2. => Optic k is s t u v
  3. -> Optic l js u v a b
  4. -> Optic m ks s t a b
#

Compose two optics of compatible flavours.

Returns an optic of the appropriate supertype. If either or both optics are indexed, the composition preserves all the indices.

value(%%)
  1. :: AppendIndices is js ks
  2. => Optic k is s t u v
  3. -> Optic k js u v a b
  4. -> Optic k ks s t a b
#

Compose two optics of the same flavour.

Normally you can simply use (%) instead, but this may be useful to help type inference if the type of one of the optics is otherwise under-constrained.

value(%&)
  1. :: Optic k is s t a b
  2. -> Optic k is s t a b -> Optic l js s' t' a' b'
  3. -> Optic l js s' t' a' b'
#

Flipped function application, specialised to optics and binding tightly.

Useful for post-composing optics transformations:

Example1 expression
toListOf (ifolded %& ifiltered (\i s -> length s <= i)) ["", "a","abc"]["","a"]

Monoid structures

0 declarations

Fold-like optics admit various monoid structures (e.g. see Optics.Fold#monoids). There is no Semigroup or Monoid instance for Optic, however, because there is not a unique choice of monoid to use, and the (<>) operator could not be used to combine optics of different kinds.

Indexed optics

9 declarations

See the "Indexed optics" section of the overview documentation in the Optics module of the main optics package for more details on indexed optics.

typetype IxList = [Type]
#

A list of index types, used for indexed optics.

typetype NoIx = '[]
#

An alias for an empty index-list

typetype WithIx i = '[i]
#

Singleton index list

classclass AppendIndices (xs :: IxList) (ys :: IxList) (ks :: IxList) | xs ys -> ks where
#

In pseudo (dependent-)Haskell, provide a witness

foldr f (foldr f init xs) ys = foldr f init (ys ++ xs)
   where f = (->)
Instances3AppendIndices
  • xs ~ zs => AppendIndices xs '[] zsDefined in optics-core-0.4.1.1 · Optics.Internal.Optic.TypeLevel

    If the second list is empty, we can pick the first list even if nothing is known about it.

  • ys ~ zs => AppendIndices '[] ys zsDefined in optics-core-0.4.1.1 · Optics.Internal.Optic.TypeLevel
  • AppendIndices xs ys ks => AppendIndices (x ': xs) ys (x ': ks)Defined in optics-core-0.4.1.1 · Optics.Internal.Optic.TypeLevel
classclass NonEmptyIndices (is :: IxList)
#

Check whether a list of indices is not empty and generate sensible error message if it's not.

Instances2NonEmptyIndices
classclass is ~ '[i] => HasSingleIndex (is :: IxList) i
#

Generate sensible error messages in case a user tries to pass either an unindexed optic or indexed optic with unflattened indices where indexed optic with a single index is expected.

Instances7HasSingleIndex, …
  • (TypeError ('Text "Indexed optic is expected"), '[] ~ '[i]) => HasSingleIndex '[] iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
  • HasSingleIndex '[i] iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
  • (TypeError ('Text "Use (<%>) or icompose to combine indices of type " ':<>: ShowTypes is), is ~ '[i1, i2], is ~ '[i]) => HasSingleIndex '[i1, i2] iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
  • (TypeError ('Text "Use icompose3 to combine indices of type " ':<>: ShowTypes is), is ~ '[i1, i2, i3], is ~ '[i]) => HasSingleIndex '[i1, i2, i3] iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
  • (TypeError ('Text "Use icompose4 to combine indices of type " ':<>: ShowTypes is), is ~ '[i1, i2, i3, i4], is ~ '[i]) => HasSingleIndex '[i1, i2, i3, i4] iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
  • (TypeError ('Text "Use icompose5 to flatten indices of type " ':<>: ShowTypes is), is ~ '[i1, i2, i3, i4, i5], is ~ '[i]) => HasSingleIndex '[i1, i2, i3, i4, i5] iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
  • (TypeError ('Text "Use icomposeN to flatten indices of type " ':<>: ShowTypes is), is ~ (i1 ': i2 ': i3 ': i4 ': i5 ': i6 ': is'), is ~ '[i]) => HasSingleIndex (i1 ': i2 ': i3 ': i4 ': i5 ': i6 ': is') iDefined in optics-core-0.4.1.1 · Optics.Internal.Indexed
familytype family Curry (xs :: IxList) y where
#

Curry a type-level list.

In pseudo (dependent-)Haskell:

Curry xs y = foldr (->) y xs

Equations

classclass CurryCompose (xs :: IxList) where
#

Class that is inhabited by all type-level lists xs, providing the ability to compose a function under Curry xs.

Methods

  • composeN :: (i -> j) -> Curry xs i -> Curry xs j

    Compose a function under Curry xs. This generalises (.) (aka fmap for (->)) to work for curried functions with one argument for each type in the list.

Instances2CurryCompose
  • CurryCompose '[]Defined in optics-core-0.4.1.1 · Optics.Internal.Optic.TypeLevel
  • CurryCompose xs => CurryCompose (x ': xs)Defined in optics-core-0.4.1.1 · Optics.Internal.Optic.TypeLevel

Base re-exports

2 declarations
value(&) :: a -> (a -> b) -> b
#

& is a reverse application operator. This provides notational convenience. Its precedence is one higher than that of the forward application operator $, which allows & to be nested in $.

This is a version of flip id, where id is specialized from a -> a to (a -> b) -> (a -> b) which by the associativity of (->) is (a -> b) -> a -> b. flipping this yields a -> (a -> b) -> b which is the type signature of &

Examples
Example1 expression
5 & (+1) & show"6"
Example1 expression
sqrt $ [1 / n^2 | n <- [1..1000]] & sum & (*6)3.1406380562059946
value(<&>) :: Functor f => f a -> (a -> b) -> f b
#

Flipped version of <$>.

(<&>) = flip fmap
Examples

Apply (+1) to a list, a Just and a Right:

Example1 expression
Just 2 <&> (+1)Just 3
Example1 expression
[1,2,3] <&> (+1)[2,3,4]
Example1 expression
Right 3 <&> (+1)Right 4