
Optics should be used. Optics should be used with awareness.
Before we can start talking about the most common approaches to using optics, the problems they solve, naming conventions, concrete libraries, and techniques; we have to cover the basic terminology and building blocks.
In this section, we’re going to give an overview of optics:
What is the difference between optics and lenses?
What is the difference between lenses and lens, optics and optics?
What are the major optics, and what can they do?
Note that this is not a comprehensive tutorial on optics — it’s a simplified overview so we can speak the same language later in the course.
Optics and lenses don’t have a spotless reputation. Most people either fear and avoid them or love them so much that they use them for everything. Both extremes push other people and optics away from reaching their full potential.
This section covers one of the most significant use cases for optics.
This section covers one of the worst use cases for optics: accessing and modifying simple records.
We’ll answer these questions:
Why do Haskell developers try to use optics with records?
Why should Haskell developers NOT use optics for simple record updates?
What should Haskell developers use for simple record updates?
The diversity in the ecosystem gives rise to many different practices and conventions. If you want to succeed, you have to put some effort into making choices to maintain cohesion.
(Technically, you can make these choices later, but it makes sense to cover these earlier in the course.)
This section highlights the questions you need to answer to adopt optics for your project:
Which encoding to use?
Should we generate or write optics by hand?
How explicit should the types be?
Should we use operators, functions, or both?
What is the naming convention?
How do we import optics?
The approach lies somewhere in between using a “full” optics library and a standard record syntax. We’re going to cover how generic lenses work and the two most popular libraries that provide generic lenses: generic-lens and optics-core.
In this section, we are going to talk about the lens library: creating optics, various functionality, free optics, and drawbacks.
Libraries: microlens and lens-simple
Let’s say you are sold on using lenses, but the lens library feels too heavyweight.
If you need a lighter alternative, you can use microlens or lens-simple; both provide a subset of the lens library with a smaller dependency tree.
The optics library is quite similar in functionality to the lens library but uses a different encoding: the (indexed) profunctor encoding instead of van Laarhoven encoding.
Before we wrap up, let’s try something else.
Various Haskell libraries provide an optic interface to work with their data. For instance, the lens-aeson library provides traversals and prisms for aeson, which we can use to interact with JSON without using intermediate Haskell data types.
In this section, we’re going to use a combination of libraries: aeson, lens, and lens-aeson.
Free bonus from our experts:)
Optics should be used, but they should be used with awareness.
Optics allow us to read and modify parts of different data structures, such as fields of records, variants of unions, or elements of containers.
This course is not a generic overview of optics — instead, we’ll focus on why optics are fantastic, when to use them, when not to use them, and how to use them in the production code.
Most people either fear and avoid them or love them so much that they use them for everything. We’re going to cover the most common ways of using optics:
Use optics to work with simple records (bad idea).
Use (generic) lenses to work with simple and nested records.
Use optics with specific data and libraries (e.g. lens-aeson, amazonka).
Use optics here and there for complex data and deeply nested records.
This course will review optics, cover the most popular encodings, the problems optics solve, naming conventions, concrete libraries, and techniques. We’ll also learn how to use optics to work with JSON. But we'll not discuss who will win in a fight: Joker from profunctors or Twan van Laarhoven.
This course is for people who:
want to actually start using optics;
want to introduce optics to their production code;
want to understand how to choose an optic library;
want to find an ergonomic way to deal with Haskell records;
or want to find their comfort zone of using optics.
This course is not for people who:
want another optics overview;
want another theoretical explanation on how to build an optic library;
want to use and understand fancy operators;
or want to use optics for everything.
Throughout the course, we’re going to cover a few libraries:
lens
generic-lens
optics
lens-aeson
We expect that you are familiar with Haskell and a few extensions, such as OverloadedStrings.
We’ll use DataKinds, DeriveGeneric, DuplicateRecordFields, FlexibleContexts, FunctionalDependencies, NamedFieldPuns, OverloadedLabels, RecordWildCards, TemplateHaskell, TypeApplications, and a few others.
We’ll give a one-two sentence explanation when we enable each extension or dive deeper when it’s crucial. So you don’t have to know them in advance for this course. But if you want to — see our course on extensions.