# Can i haz? Part 3: extending the Has pattern

November 11, 2019 //

Once we scrapped the boilerplate for the `Has` pattern, the next obvious question is if we can generalize further. And, turns out, we can!

In this post we’ll see how some algebraic considerations help us to discover one more pattern useful with `MonadError` (and a `Generic` implementation thereof), and we’ll also update our `Has` class with one more method that brings it closer to something lens-like and makes it useful with writable environments like `MonadState`.

## Inverting the arrows

Given some structure, a true algebraist (which I’m not by any means) always wonders what happens if one turns the arrows in that struсture, obtaining a categorical dual.

In this particular case we have a single arrow `extract` in the structure `Has`:

``````class Has part record where
extract :: record -> part``````

Let’s invert it and prepend `co` everywhere:

``````class CoHas copart corecord where
coextract :: copart -> corecord``````

You might already have an intuition about what `CoHas` might be, but let’s proceed turning the arrows based on pure formalism for now.

`Path` and `Combine` are boring and have no good applicable structure, so we leave them as is. `Search`, on the other hand, is more interesting. Recall the definition we used when we built the generic implementation for `Has`:

``````type family Search part (grecord :: k -> *) :: MaybePath where
Search part (K1 _ part) = 'Found 'Here
Search part (K1 _ other) = 'NotFound
Search part (M1 _ _ x) = Search part x
Search part (l :*: r) = Combine (Search part r) (Search part r)
Search _ _ = 'NotFound``````

Note the next-to-last case, which mentions `f :*: g`. The dual of a product is a sum, so the object dual to `Search` would be:

``````type family CoSearch copart (gcorecord :: k -> *) :: MaybePath where
CoSearch copart (K1 _ copart) = 'Found 'Here
CoSearch copart (K1 _ other) = 'NotFound
CoSearch copart (M1 _ _ x) = CoSearch copart x
CoSearch copart (l :+: r) = Combine (CoSearch copart l) (CoSearch copart r)
CoSearch _ _ = 'NotFound``````

Generic `GCoHas` follows the same pattern:

``````class GCoHas (path :: Path) copart gcorecord where
gcoextract :: Proxy path -> copart -> gcorecord p``````

And so do the instances:

``````instance GCoHas 'Here corecord (K1 i corecord) where
gcoextract _ = K1

instance GCoHas path copart corecord => GCoHas path copart (M1 i t corecord) where
gcoextract proxy = M1 . gcoextract proxy

instance GCoHas path copart l => GCoHas ('L path) copart (l :+: r) where
gcoextract _ = L1 . gcoextract (Proxy :: Proxy path)

instance GCoHas path copart r => GCoHas ('R path) copart (l :+: r) where
gcoextract _ = R1 . gcoextract (Proxy :: Proxy path)``````

Note that nothing happens with the position of `Proxy` here, which totally makes sense: `Proxy` is only used as a hint to the type checker to help deducing the right type, and it doesn’t bear any deep semantics within the structure we’re considering.

The implementation of the type class is obvious given the above:

``````class CoHas copart corecord where
coextract :: copart -> corecord

default coextract :: forall path. (Generic corecord, SuccessfulSearch copart corecord path) => copart -> corecord
coextract = to . gcoextract (Proxy :: Proxy path)``````

### Interpretation

Now let’s think about the meanings.

• `record` is some product type, `corecord` is dual to it, so it’s some sum type. Indeed, `sum` might be a better name for it.
• `part` is a field in the `record`, `copart` is dual to it, so it’s one of the options in the `sum`. Indeed, `option` might be a better name for it.
• `extract` takes a `record` and produces a `part` of that `record`. `coextract`, on the other hand, takes `option` and produces a `sum`. One obvious interpretation (that also follows the implementation) is that `coextract` just creates a value of the `sum` type given one of the `option`s. Say, `inject` might be a better name for it.

So, to sum it up: `CoHas option sum` means that we can `inject` values of type `option` into the `sum` type. We have `Either` as a prime example:

``instance SuccessfulSearch a (Either l r) path => CoHas a (Either l r)``

So, if `l` is not the same as `r`, we can create `Either l r` out of `l` (and out of `r`, of course) via the `CoHas` class and its `inject` method.

Yes, we also have the same type safety and soundness guarantees: this `CoHas option sum` is derivable (via `Generics`) iff there is one and only one way to construct `sum` set to the `option`. So, for example, the following won’t work:

``````data AppError = QaDbError DbError
| ProdDbError DbError
deriving (CoHas DbError)``````

Where could `CoHas` be useful? One might consider

### `CoHas` and `MonadError`

We write `MonadReader r m, Has FooEnv r` to denote that the environment `r` contains a value of type `FooEnv`. Similarly we might write `MonadError e m, CoHas FooErr e` to denote that the error context could be used to report about errors of type `FooErr`.

This again might help modularity: assume our good old modules we considered earlier (the DB layer, the web server and the cron scheduler) might each report an error of their own type. Then we could have an application-level error type

``````data AppError
= AppDbError DbError
| AppWebServerError WebServerError
| AppCronError CronError
deriving (Generic, CoHas DbError, CoHas WebServerError, CoHas CronError)``````

that could be used to collect errors from all of the components, just as we used `AppConfig` to provide the configuration for all of the components at once.

Bottom line: using purely algebraic considerations, we arrived at yet another useful (and free, in a sense) generalization of our approach!

## Updating `record`s

Alright, back to the `Has` class.

We’ve learned how to extract the values of some type `part` out of a `record` containing them. What else can we do?

Let’s say we have a function `f :: part -> part`. Then we can obtain a function transforming `record`s “for free”, merely by applying `f` to the `part` contained in the `record`:

``update :: (part -> part) -> record -> record``

If you’re familiar with the concept of the lenses, you’ve quite likely noticed that `update` paired with `extract` essentially allows defining one’s own lenses, and this is not a coincidence, but we will not delve too deep into that.

Anyway, after all our exercises with `extract` and `inject`/`coextract` the generic code for `update` is a routine.

First we add the `gupdate` method to the `GHas` helper class. The only real difference is that we get the generic representation back as opposed to a “real” type for `gextract`:

``````class GHas (path :: Path) part grecord where
...
gupdate :: Proxy path -> (part -> part) -> grecord p -> grecord p``````

Then we add the implementation of `gupdate` to the instances of `GHas` we already had, keeping in mind we should produce the appropriate `Generic` value:

``````instance GHas 'Here rec (K1 i rec) where
...
gupdate _ f (K1 x) = K1 \$ f x

instance GHas path part record => GHas path part (M1 i t record) where
...
gupdate proxy f (M1 x) = M1 (gupdate proxy f x)

instance GHas path part l => GHas ('L path) part (l :*: r) where
...
gupdate _ f (l :*: r) = gupdate (Proxy :: Proxy path) f l :*: r

instance GHas path part r => GHas ('R path) part (l :*: r) where
...
gupdate _ f (l :*: r) = l :*: gupdate (Proxy :: Proxy path) f r``````

Our final step is to add the corresponding `update` method to `Has` and write a default implementation for it:

``````class Has part record where
...

update :: (part -> part) -> record -> record

default update :: forall path. (Generic record, SuccessfulSearch part record path) => (part -> part) -> record -> record
update f = to . gupdate (Proxy :: Proxy path) f . from``````

And that’s it! Easy-peasy.

### `update` and `MonadState`

`extract` has a nice use with `MonadReader`: we replace `MonadReader Foo m` with `(MonadReader r m, Has Foo r)` and use `extract` appropriately in the bodies of the corresponding functions. What uses does `update` have?

Not much with `MonadReader`, but there is a very similar monad that supports modifications: `MonadState`. So, now instead of `MonadState FooState m` we also write `(MonadState s m, Has FooState s)`, obtaining nice composable and reusable stateful functions!

What we’ve achieved is basically a generalizaton of the `Has` pattern to writable environments!

It’s also tempting to reverse the arrows once again and seeing what happens with `update`, but that requires some less trivial math, so we’ll leave that out for another post. Stay tuned!