While writing code to rewrite some Dhall syntax trees, I noticed a cool
connection between the core `uniplate`

operation and optics. This will be old news to advanced
`lens`

users, but I think it’s worth pointing out. The
`uniplate`

package’s original
`uniplate :: Uniplate a => a -> ([a], [a] -> a)`

is
an early attempt at a “traversal” optic, properly expressed in
`lens`

by `plate :: Plated a => Traversal' a a`

.

The `uniplate`

library provides low-boilerplate ways to
query and rewrite self-similar data structures; the
`uniplate`

function from `class Uniplate a`

is its
fundamental operation. Let’s look at the original definition, from the
2007 paper Uniform
Boilerplate and List Processing:

```
class Uniplate a where
uniplate :: a -> ([a], [a] -> a)
-- An example data type and instance
data Expr = Lit Int | Negate Expr | Add Expr Expr
instance Uniplate Expr where
Lit i) = ([], \[] -> Lit i)
uniplate (Negate e) = ([e], \[e'] -> Negate e')
uniplate (Add e1 e2) = ([e1, e2], \[e1', e2'] -> Add e1' e2') uniplate (
```

`uniplate`

extracts from a value of type `T`

any immediate children of type `T`

, and provides a function
to reassemble the original structure with new children. From this, we
can define operations like `transform`

, which applies a
function everywhere it can be applied, in a bottom-up way:

```
transform :: Uniplate a => (a -> a) -> a -> a
= rebuild $ map (transform f) as
transform f a where (as, rebuild) = uniplate a
```

Look closely at the type of the `uniplate`

operation: it
extracts `[a]`

from a structure, and provides a function to
assign a new `[a]`

into a structure. This is exactly what a
**get/set lens** does:

```
-- As a record:
data GetSetLens s a = GetSetLens
get :: s -> a
{ set :: s -> a -> s
,
}
-- As a type alias for a tuple:
type GetSetLens s a = (s -> a, s -> a -> s)
-- Factor out the common 's' parameter:
type GetSetLens s a = s -> (a, a -> s)
class Uniplate a where
uniplate :: GetSetLens a [a]
```

The example `Uniplate`

instance shows us that this lens
requires careful use: we must return a list of exactly the same length
as the one we are given. Now that we’ve noticed a connection between
`Uniplate`

and lenses, is there a better optic we could use?
Yes — traversals are optics that focus zero or more targets, so we could
rebuild the `uniplate`

library on top of an operation that
provides a `Traversal' a a`

. This is what `lens`

does with `Control.Lens.Plated`

:

```
class Plated a where
plate :: Traversal' a a
```

If you are unable to define a `Plated`

instance on a type
(e.g., you do not want to introduce an orphan instance on a type you do
not own), `lens`

also provides a helper,
`uniplate :: Data a => Traversal' a a`

. Interestingly,
`lens`

also provides a `partsOf`

combinator which collects the foci of an optic into a list:

```
-- Usable as:
partsOf :: Iso' s a -> Lens' s [a]
partsOf :: Lens' s a -> Lens' s [a]
partsOf :: Traversal' s a -> Lens' s [a]
partsOf :: Fold s a -> Getter s [a]
partsOf :: Getter s a -> Getter s [a]
-- The real type signature:
partsOf :: Functor f => Traversing (->) f s t a a -> LensLike f s t [a] [a]
```

Its haddock even says that it “resembles an early version of the
`uniplate`

(or `biplate`

) type” and that “you
really should try to maintain the invariant of the number of children in
the list”.

And that brings us full circle; we can get a van Laarhoven version of
our original `uniplate`

lens using `Data.Data.Lens.uniplate`

:

```
:: Data a => Traversal' a a
Data.Data.Lens.uniplate :: Data a => Lens' a [a] partsOf Data.Data.Lens.uniplate
```

This is one of my favourite things about programming in Haskell: seeing that library authors have carefully refined concepts like “view the self-similar children of a structure” into ever more powerful and composable forms, and being able to notice the different stages in that evolution.