Last active
August 12, 2025 12:57
-
Star
(110)
You must be signed in to star a gist -
Fork
(6)
You must be signed in to fork a gist
-
-
Save ChrisPenner/1f7b6923448b3396a45d04a2b6b9d066 to your computer and use it in GitHub Desktop.
Revisions
-
ChrisPenner revised this gist
Jan 2, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -136,7 +136,7 @@ The optic in the first **column** is the optic you **have**, the other column he | Fold | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Getter | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Setter | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | Traversal | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | Lens | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Review | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | | Prism | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | -
ChrisPenner renamed this gist
Jan 1, 2020 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 4 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,6 +3,9 @@ The following are appendices from [Optics By Example](https://leanpub.com/optics-by-example/), a comprehensive guide to optics from beginner to advanced! If you like the content below, there's **plenty** more where that came from; [pick up the book](https://leanpub.com/optics-by-example/)! * [Operators](#operator-cheat-sheet) * [Composition Guide](#optic-composition-table) * [Substitution Guide](#optic-compatibility-chart) * [Optical Constarints and Types](#optic-constraints-and-types) ## Operator Cheat Sheet @@ -139,7 +142,7 @@ The optic in the first **column** is the optic you **have**, the other column he | Prism | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | | Iso | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ## Optic Constraints and Types When reading type-errors or strange optics signatures you can usually guess the type of optic an operation needs by matching the constraints against the following chart. -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,8 @@ The following are appendices from [Optics By Example](https://leanpub.com/optics-by-example/), a comprehensive guide to optics from beginner to advanced! If you like the content below, there's **plenty** more where that came from; [pick up the book](https://leanpub.com/optics-by-example/)! * [Operators](#operator-cheat-sheet) ## 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. -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 8 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -177,3 +177,11 @@ Composing optics adds **constraints** together, then running an optic with an ** | review (#) | Tagged | | traverseOf (%%~) | None | | matching | Market | --- Thanks for reading! If you learned something, consider getting the rest of the book, this cheat sheet only scratches the surface! You can get [Optics By Example here](https://leanpub.com/optics-by-example/). Thanks! Feel free to share this cheat-sheet with your friends. -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 83 additions and 80 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,84 +1,6 @@ # Optics By Example Cheat Sheets The following are appendices from [Optics By Example](https://leanpub.com/optics-by-example/), a comprehensive guide to optics from beginner to advanced! If you like the content below, there's **plenty** more where that came from; [pick up the book](https://leanpub.com/optics-by-example/)! ## Operator Cheat Sheet @@ -174,3 +96,84 @@ Nothing Just (2,4) ``` ## Optic Composition Table This table is adapted from the documentation of the Scala optics library [**Monocle**](https://julien-truffaut.github.io/Monocle/optics.html). 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`. ## 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 **Prism**s 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. The optic in the first **column** is the optic you **have**, the other column headers represent the type you'd like to **use it as**. | | Fold | Getter | Setter | Traversal | Lens | Review | Prism | Iso | | ---------- | ---- | ------- | ------ | --------- | ---- | ------ | ----- | --- | | Fold | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Getter | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Setter | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | Traversal | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | Lens | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Review | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | | Prism | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | | Iso | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ## Optic Ingredients When reading type-errors or strange optics signatures you can usually guess the type of optic an operation needs by matching the constraints against the following chart. Remember that most optics take the form: ```haskell (a -> f b) -> (s -> f t) ``` However `Iso`s, `Prism`s and `Review`s generalize over the Profunctor type and thus can also have constraints on `p`: ```haskell p a (f b) -> p s (f t) ``` Keep this in mind when reading the chart. | Optic | Constraints | |-----------------------|------------------------------- | | **Lens** | Functor f | | **Fold** | Contravariant f, Applicative f | | **Traversal** | Applicative f | | **Setter** | Settable f | | **Getter** | Contravariant f, Functor f | | **Iso** | Functor f, Profunctor p | | **Prism** | Applicative f, Choice p | | **Review** | Settable f, Profunctor p, Bifunctor p | Composing optics adds **constraints** together, then running an optic with an **action** matches a data type which fulfills those constraints. Here's a table of lens actions and the data-type they use to "run" the optics you pass to them: | Action | Data type | | --------------------------------------------------|-----------| | view (^.) | Const | | set (.~) | Identity | | over (%~) | Identity | | fold queries: (toListOf, sumOf, lengthOf, etc.) | Const | | review (#) | Tagged | | traverseOf (%%~) | None | | matching | Market | -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -26,6 +26,8 @@ The following chart details which optics are valid substitutions for one another As an example, let's say we were curious if all **Prism**s 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. The optic in the first **column** is the optic you **have**, the other column headers represent the type you'd like to **use it as**. | | Fold | Getter | Setter | Traversal | Lens | Review | Prism | Iso | | ---------- | ---- | ------- | ------ | --------- | ---- | ------ | ----- | --- | | Fold | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 9 additions and 9 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -28,14 +28,14 @@ As an example, let's say we were curious if all **Prism**s are a valid **Travers | | Fold | Getter | Setter | Traversal | Lens | Review | Prism | Iso | | ---------- | ---- | ------- | ------ | --------- | ---- | ------ | ----- | --- | | Fold | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Getter | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Setter | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | Traversal | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | Lens | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Review | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | | Prism | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | | Iso | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ## Optic Ingredients @@ -136,7 +136,7 @@ E:Control.Lens.Fold | `-` | **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 | -
ChrisPenner revised this gist
Jan 1, 2020 . 1 changed file with 154 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,8 +1,6 @@ ## Optic Composition Table This table is adapted from the documentation of the Scala optics library [**Monocle**](https://julien-truffaut.github.io/Monocle/optics.html). 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. @@ -21,3 +19,156 @@ The type of an optic is determined by collecting all the constraints of all comp | **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`. ## 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 **Prism**s 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 | ## Optic Ingredients When reading type-errors or strange optics signatures you can usually guess the type of optic an operation needs by matching the constraints against the following chart. Remember that most optics take the form: ```haskell (a -> f b) -> (s -> f t) ``` However `Iso`s, `Prism`s and `Review`s generalize over the Profunctor type and thus can also have constraints on `p`: ```haskell p a (f b) -> p s (f t) ``` Keep this in mind when reading the chart. | Optic | Constraints | |-----------------------|------------------------------- | | **Lens** | Functor f | | **Fold** | Contravariant f, Applicative f | | **Traversal** | Applicative f | | **Setter** | Settable f | | **Getter** | Contravariant f, Functor f | | **Iso** | Functor f, Profunctor p | | **Prism** | Applicative f, Choice p | | **Review** | Settable f, Profunctor p, Bifunctor p | Composing optics adds **constraints** together, then running an optic with an **action** matches a data type which fulfills those constraints. Here's a table of lens actions and the data-type they use to "run" the optics you pass to them: | Action | Data type | | --------------------------------------------------|-----------| | view (^.) | Const | | set (.~) | Identity | | over (%~) | Identity | | fold queries: (toListOf, sumOf, lengthOf, etc.) | Const | | review (#) | Tagged | | traverseOf (%%~) | None | | matching | Market | ## 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** (`..`). ```haskell "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. ```haskell >>> 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 | | `%` | **Mod**ify 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 `mappend`s (`<>`) a new value to the focus. ```haskell >>> ["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: ```haskell >>> runState (itraversed <<%@= \k v -> "item: " <> k <> ", quantity: " <> v) (M.singleton "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. ```haskell >>> (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) ``` -
ChrisPenner created this gist
Jan 1, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,23 @@ ## Optic Composition Table This table is adapted from the documentation of the Scala optics library **Monocle**[^monocle]. I've simply altered it to match the `lens` library. [^monocle]: https://julien-truffaut.github.io/Monocle/optics.html 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`.