<p><code>optics</code> do form a category where the objects are <code>(Type, Type)</code>. However,
the <code>Optic</code> type is defined with</p>
<pre><code>newtype Optic k is s t a b = ...
</code></pre>
<p>The domain and the codomain of <code>Optic</code> are curried into 4 type arguments <code>s t a b</code>, but the <code>Category</code> typeclass in Haskell requires the domain and the codomain to be the last two type arguments of the type constructor.</p>
<p>Alternatively, the <code>Optic</code> type can be defined with</p>
<pre><code>newtype Optic k is (st :: (Type, Type)) (ab :: (Type, Type)) = ...
</code></pre>
<p>This allows a <code>Category</code> instance, however it is less user-friendly, since the user would need to use <code>DataKinds</code> tuples to specify the types.</p>

CC BY-SA 4.0
2022-01-24T20:42:16.477Z
2022-01-24T20:42:16.477Z
Szumi Xie
<p>The <a href="https://hackage.haskell.org/package/optics-0.4/docs/Optics.html" rel="nofollow noreferrer"><code>optics</code></a> Haskell package is an alternative to the famous <a href="https://hackage.haskell.org/package/lens" rel="nofollow noreferrer"><code>lens</code></a> package.</p>
<p><code>lens</code> uses a van Laarhoven encoding, encoding lenses as functions. This means than not only do <code>lens</code> lenses form a category, but they actually compose using standard function composition. In other words, they can compose using the old-fashioned <code>.</code> operator, even before the <code>Category</code> typeclass.</p>
<p><code>optics</code>, in contrast, defines lenses using opaque newtypes. It should still be possible to get access to composition via the <code>.</code> operator by defining a <code>Category</code> instance. However, <code>optics</code> doesn't do that, but instead defines a new <code>%</code> composition operator. <a href="https://hackage.haskell.org/package/optics-0.4/docs/Optics.html" rel="nofollow noreferrer">The docs</a> have this to say:</p>
<blockquote>
<p>The (.) operator from Control.Category cannot be used to compose optics [..] because it would not support type-changing optics or composing optics of different kinds.</p>
</blockquote>
<p>and</p>
<blockquote>
<p>optics must use a different composition operator (%). Optic does not quite form a Category, thanks to type-changing optics.</p>
</blockquote>
<p>This leaves me very puzzled. <a href="http://comonad.com/reader/2012/mirrored-lenses/" rel="nofollow noreferrer">It is well known</a> that <code>lens</code>' van Laarhoven lenses <em>do</em> support type-changing (polymorphic update), whilst still being a category by construction, via their underlying function type.</p>
<p>Can someone explain why it's impossible for <code>optics</code> lenses to form a category, even though they are functionally equivalent to van Laarhoven?</p>
<p>Is it possible to define lenses more opaque than <code>lens</code> whilst still forming a lawful category?</p>

<ct.category-theory><haskell>
Why can't opaque optics form a category?
Ari Fordsham
# Why can't opaque optics form a category?

(Asked by: username_0 on 2022-01-23)

The [`optics`](https://hackage.haskell.org/package/optics-0.4/docs/Optics.html) Haskell package is an alternative to the famous [`lens`](https://hackage.haskell.org/package/lens) package.

`lens` uses a van Laarhoven encoding, encoding lenses as functions. This means than not only do `lens` lenses form a category, but they actually compose using standard function composition. In other words, they can compose using the old-fashioned `.` operator, even before the `Category` typeclass.

`optics`, in contrast, defines lenses using opaque newtypes. It should still be possible to get access to composition via the `.` operator by defining a `Category` instance. However, `optics` doesn't do that, but instead defines a new `%` composition operator. [The docs](https://hackage.haskell.org/package/optics-0.4/docs/Optics.html) have this to say:

> The (.) operator from Control.Category cannot be used to compose optics [..] because it would not support type-changing optics or composing optics of different kinds.

and

> optics must use a different composition operator (%). Optic does not quite form a Category, thanks to type-changing optics.

This leaves me very puzzled. [It is well known](http://comonad.com/reader/2012/mirrored-lenses/) that `lens`' van Laarhoven lenses *do* support type-changing (polymorphic update), whilst still being a category by construction, via their underlying function type.

Can someone explain why it's impossible for `optics` lenses to form a category, even though they are functionally equivalent to van Laarhoven?

Is it possible to define lenses more opaque than `lens` whilst still forming a lawful category?

**Tags:** ct.category-theory, haskell


---

## 1 answers

### Answer by username_1 on 2022-01-24. Score: 1 | Accepted answer

`optics` do form a category where the objects are `(Type, Type)`. However,
the `Optic` type is defined with

```
newtype Optic k is s t a b = ...

```

The domain and the codomain of `Optic` are curried into 4 type arguments `s t a b`, but the `Category` typeclass in Haskell requires the domain and the codomain to be the last two type arguments of the type constructor.

Alternatively, the `Optic` type can be defined with

```
newtype Optic k is (st :: (Type, Type)) (ab :: (Type, Type)) = ...

```

This allows a `Category` instance, however it is less user-friendly, since the user would need to use `DataKinds` tuples to specify the types.


---

