# Using \`OverloadedRecordDot\` with "optics"

**URL:** <https://discourse.haskell.org/t/using-overloadedrecorddot-with-optics/13490>\
**Category:** Learn\
**Created:** [January 4, 2026, 10:16pm UTC](https://discourse.haskell.org/t/using-overloadedrecorddot-with-optics/13490 "2026-01-04T22:16:32Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![danidiaz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/danidiaz/32/92_2.png) [@danidiaz](https://discourse.haskell.org/u/danidiaz)\
**Post date:** [January 4, 2026, 10:16pm UTC](https://discourse.haskell.org/t/using-overloadedrecorddot-with-optics/13490/1 "2026-01-04T22:16:32Z")

</div>

I like the [“optics”](https://hackage.haskell.org/package/optics-core) library. I like [`OverloadedRecordDot`](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/overloaded_record_dot.html). I would like to use dot-access syntax for nested record updates. If I have an optic `foo` that focuses on type `R`, and type `R` has a field named `bar`, `foo.bar` (dot access) would be a new optic that focuses on the field `bar`. How to achieve this?

We can define an (admittedly weird) [`HasField`](https://hackage-content.haskell.org/package/base-4.22.0.0/docs/GHC-Records.html#t:HasField) orphan instance _on the [`Optic`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Optic.html#t:Optic) type itself_. Note that this is only possible because `Optic`, unlike the lenses from [“lens”](https://hackage.haskell.org/package/lens), is a true abstract type, not simply a type synonym for polymorphic functions:

```haskell
instance
    (GField (name :: Symbol) u v a b,
    JoinKinds k A_Lens m,
    AppendIndices is NoIx ks)
    =>
    HasField name (Optic k is s t u v) (Optic m ks s t a b) where
        getField = (% gfield @name)

```

That needs some explaining. We have sets of four type variables `s t u v`, `u v a b`, `s t a b` instead of pairs of type variables, to account for type-changing updates. Ignoring the type-changing complexity, the idea is that if we have a lens that focuses on `u`, and type `u` has a field named `name` of type `a` whose lens obtainable through the [`GField`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Generic.html#t:GField) generics machinery, the dot accesor can just [compose](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Optic.html#v:-37-) the original lens with the field lens.

What about [`JoinKinds`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Optic.html#t:JoinKinds) and [`AppendIndices`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Optic.html#t:AppendIndices)? The “optics” library keeps track of an optics’ properties in the `k is` type parameters and, when composing optics, these type families combine the properties of each component. When accessing a field, the optic kind will be [`A_Lens`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Internal-Optic-Types.html#t:A_Lens), and we keep no extra index ([`NoIx`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Optic.html#t:NoIx)) information.

But how to get the _initial_ lens to start accessing? We can begin with the “identity” optic, which in “optics” is an [`Iso`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Iso.html#t:Iso) called [`equality`](https://hackage.haskell.org/package/optics-core-0.4.1.1/docs/Optics-Iso.html#v:equality). Let’s rename it to `the`:

```haskell
the :: Iso a b a b
the = equality

```

Now we can have syntax like `whole & the.part.subpart.yet.ooo .~ "newval"`.

There’s room for improvement though. One problem is that we are wedded to the `GField` machinery. But we would like the dot access to work with other ways of defining lenses, like TH, `HasField`/`SetField`, and maybe others. Different records could use different ways.

We can achieve that by defining a separate helper typeclass parameterized by the “method” we want to use for deriving the optics. I’ve implemented that in the [dani-optics-dot](https://github.com/danidiaz/dani-optics-dot) repo.

---

<div class="post-metadata">

**Author:** ![Kleidukos](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/kleidukos/32/1213_2.png) [@Kleidukos](https://discourse.haskell.org/u/Kleidukos)\
**Post date:** [January 4, 2026, 10:45pm UTC](https://discourse.haskell.org/t/using-overloadedrecorddot-with-optics/13490/2 "2026-01-04T22:45:27Z")

</div>

Very cool, thanks for prototyping on this. 🙂
