<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.


---

