, 24 tweets, 11 min read Read on Twitter
Welcome to the seventh episode of #monadicmonday! Today we'll talk a bit about functional optics: lenses, prisms, folds and traversals.
History of lenses started in 2009 with "The Essence of the Iterator Pattern" paper, which started a whole lot of cascading publications, leading to current `lens` package for Haskell and various implementations in different languages.
I will use an awesome `monocle-ts` package from @GiulioCanti for this episode, but you may use any optics library you find suitable. The concepts are the same.

You can find more historical references at github.com/ekmett/lens/wi…
@GiulioCanti It's a common practice that we work with immutable data structures when writing in functional style. It gives us incredible guarantees about our code, but also comes with a drawback: it's hard to update (rebuild) the deeply-nested data structure. So optics to the resque!
@GiulioCanti Functional optics gives you a way of working with a complicated immutable data structures (deeply nested, recursive, etc) without explicit need to maintain the structure. Currently optics libraries heavily rely on profunctor encoding, but we will be using a much simpler one.
@GiulioCanti Consider an example in imperative style:
@GiulioCanti I should say that this way is error-prone (for example, it's easy to make a mistake and forcefully create `projects` field for all employees – even if they hadn't had it), tedious and not composable. However, there's a way to solve this problem with ease.
@GiulioCanti N.B. Bonus points are going to those who remembered the third episode and said that you can use a recursion scheme named "catamorphism" here (or simply `fold`). But today we take a look through optics at this problem.
@GiulioCanti The intuition behind optics comes straight from physics: each optic entity allows you to "focus" on some part(s) of your data structure and provide interface to interact with them.
@GiulioCanti Let's start with an `Iso`. "Iso" stands for "isomorphism", and is generally could be thought of as a pair of functions to "get" and "rebuild" the values (reverse the "get"). Please note that in general isomorphisms between any two types are not guaranteed:
@GiulioCanti One example I can think of is a pair of two "1/x" functions. Given an `y` value, "get" applies `x -> 1/x` and leaves you with `1/y`, and "reverseGet" rebuilds `y` from `1/y` applying `x -> 1/x` function again.
@GiulioCanti The other example may be a pair of "toLocaleLowerCase" and "toLocaleUpperCase" functions in JS – but if and only if we agree that an input to Iso must already be in uppercase. Law for `Iso` is the following:

reverseGet . get ≅ id
@GiulioCanti `Iso` as it is may seem to be pretty useless, because in general from any `A` you cannot obtain any `B`. But it gives a raise to the next optics – `Lens`.
@GiulioCanti `Lens<S, A>` is a pair of functions to "get" and "set" values in the structure. Please note that unlike `Iso`, `Lens` implies the structure itself is already defined, so you cannot "set" a deeply nested level if intermediate levels are missing.
@GiulioCanti Lenses are great for working with product types (tuples & objects).
@GiulioCanti Consider an example:
@GiulioCanti If you need to work with fields that may be missing, you'll need to use a `Prism` or `Optional`. They both are used for working with sum types: arrays, Options, Eithers, etc, and they are defined using a pair of functions:
@GiulioCanti If you are coming from an imperative programming background, you can think of Lens, Optional & Prism as of ways of overloading property accessors.

Another useful type of optics – `Fold`. It allows, given a Monoid for the data type `M`, to fold (reduce) its value into type `M`:
@GiulioCanti `Traversal` is an optics which can traverse (what a surprise!) data structure and perform the following operations:
@GiulioCanti Consider an example:
@GiulioCanti The best thing about optics is that it is easily composed with each other. You can start with a Lens, compose it with a Prism to zoom deeper, then compose with a Traversal to walk the inner structure, and so on.
@GiulioCanti Let's take a look at another example: given an organizational structure, calculate average age of its members.

Let's use the same data structure and example data set as in previous example:
@GiulioCanti If you want to dive into categorical view on the optics, you should read excellent article by @BartoszMilewski: bartoszmilewski.com/2017/07/07/pro…

However, it's not an entry-level work, so be prepared for complicated categorical topics like profunctor, adjoints and Tambara modules.
@GiulioCanti @BartoszMilewski As usual, the code examples for this episode are available at github.com/YBogomolov/mon…
Missing some Tweet in this thread?
You can try to force a refresh.

Like this thread? Get email updates or save it to PDF!

Subscribe to Yuriy Bogomolov
Profile picture

Get real-time email alerts when new unrolls are available from this author!

This content may be removed anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!