18 Appendices

This content is not available in the sample book. The book can be purchased on Leanpub at http://leanpub.com/optics-by-example.

18.1 Optic Composition Table

This table is adapted from the documentation of the Scala optics library Monocle1. I’ve simply altered it to match the lens library.

The value of each cell denotes the most general type you can achieve by composing the column header with the row header.

The type of an optic is determined by collecting all the constraints of all composed optics in a path. Since constraints collection acts as a set union (which is commutative) the order of composition has no effect on the resulting optic type. Therefore the following table is symmetric across its diagonal.

”–” signifies that the optics are incompatible and do not compose.

  Fold Getter Setter Traversal Prism Lens Iso
Fold Fold Fold Fold Fold Fold Fold
Getter Fold Getter Fold Fold Getter Getter
Setter Setter Setter Setter Setter Setter
Traversal Fold Fold Setter Traversal Traversal Traversal Traversal
Prism Fold Fold Setter Traversal Prism Traversal Prism
Lens Fold Getter Setter Traversal Traversal Lens Lens
Iso Fold Getter Setter Traversal Prism Lens Iso

For example, to determine which type we get by composing traverse with _Just we first check each of their types to discover that traverse is a Traversal and _Just is a Prism. We then look up the column (or row) with the header Traversal, then find the cell with the corresponding header Prism on the other axis. Performing this look up we see that the composition traversed . _Just results in a Traversal.

18.2 Optic Compatibility Chart

The following chart details which optics are valid substitutions for one another.

As an example, let’s say we were curious if all Prisms are a valid Traversal; we first find the row with Prism in the first column; then find the corresponding Traversal column and find a Yes; meaning that a Prism is a valid substitution for a Traversal.

  Fold Getter Setter Traversal Lens Review Prism Iso
Fold Yes No No No No No No No
Getter Yes Yes No No No No No No
Setter No No Yes No No No No No
Traversal Yes Yes Yes Yes No No No No
Lens Yes Yes Yes Yes Yes No No No
Review No No No No No Yes No No
Prism Yes No Yes Yes No Yes Yes No
Iso Yes Yes Yes Yes Yes Yes Yes Yes

18.3 Operator Cheat Sheet

Operators may look like an earthquake hit the mechanical keyboard factory, but there’s actually a bit of a language to the whole thing which starts to make sense after a bit of practice.

Once you get used to the ideas you can usually guess the name of a symbol which does what you need, and it’ll usually exist!

Legend for Getters

Symbol Description
^ Denotes a Getter
@ Include the index with the result
. Get a single value
.. Get a List of values
? Maybe get the first value
! Force a result or throw an exception if missing

Examples

(^@..) :: s -> IndexedFold i s a -> [(i, a)]
A getter (^) which includes the index (@) in a list of all focuses (..).
"Yarrr" ^@.. folded
[(0,'Y'),(1,'a'),(2,'r'),(3,'r'),(4,'r')]
(^?!) :: s -> Traversal' s a -> a
A getter (^) which forcibly gets (!) a possibly missing (?) value.
>>> Just "Nemo" ^?! _Just
"Nemo"
>>> Nothing ^?! _Just
*** Exception: (^?!): empty Fold
CallStack (from HasCallStack):
  error, called at src/Control/Lens/Fold.hs:1285:28 in lens
E:Control.Lens.Fold
  ^?!, called at <interactive>:1:1 in interactive:Ghci4

Legend for Setters/Modifiers

Symbol Description
. Set the focus
% Modify the focus
~ Denotes a Setter/Modifier
= Denotes a Setter/Modifier over a MonadState context
< Include the altered focus with the result
<< Include the unaltered focus with the result
%% Perform a traversal over the focus
<> mappend over the focus
? Wrap in Just before setting
+ Add to the focus
- Subtract from the focus
* Multiply the focus
// Divide the focus
|| Logically or the focus
&& Logically and the focus
@ Pass the index to the modification function

Examples

(<>~) :: Monoid a => Traversal' s a -> a -> s -> s
A setter (~) which mappends (<>) a new value to the focus.
>>> ["Polly want a", "Salty as a soup"] & traverse <>~ " cracker!"
["Polly want a cracker!","Salty as a soup cracker!"]
(<<%@=) :: MonadState s m => Traversal s s a b -> (i -> a -> b) -> m a
Modify (%) the focus from within a MonadState (=), passing the index (@) to the function as well. Also return unaltered (<<) original value.

This one’s a bit tricky:

>>> runState (itraversed <<%@= \k v -> "item: " <> k <> ", quantity: " <> v) (M.sing\
leton "bananas" "32")
("32",fromList [("bananas","item: bananas, quantity: 32")])
(%%~) :: Traversal s t a b -> (a -> f b) -> s -> f t
A setter (~) which traverses (%%) a function over the focus.
>>> (1, 2) & both %%~ (\n -> if even n then Just n else Nothing)
Nothing

>>> (2, 4) & both %%~ (\n -> if even n then Just n else Nothing)
Just (2,4)

18.4 Optic Ingredients

This content is not available in the sample book. The book can be purchased on Leanpub at http://leanpub.com/optics-by-example.