View Source
Introduction to debugging and def_raw_maker
I really hate this damn machine.
I wish that they would sell it.
It never does quite what I want,
But only what I tell it.
– Traditional
When using simple composed lenses like Lens.key(:a) |> Lens.keys([:aa, :bb])
, you don't have to understand what's happening
behind the scenes. The lens descends through key :a
, then through
keys :aa
and :bb
, and either returns a list of values or an
updated complete container (depending on whether you're using Deeply.get_all
or Deeply.update
.
But sometimes – especially if you use some of the more unusual combining lenses – you'll get surprised. I've reluctantly concluded that the surest way to un-perplex yourself is to work through the detailed steps of what's happening in the lens code. To do that, you need to understand lenses well enough to write one from scratch. That's what this guide is about.
Note: you might want to defer reading this page until you actually are perplexed or need to write a lens maker. Maybe you'll never need it!
A lens is an anonymous function created by a lens maker (a named
function). You can easily write a lens maker using def
, but the
def_raw_maker
macro handles some busywork for you. In either case, the
form of the lens function is fixed: you use a template and fill in
some blanks.
Because the template is somewhat conceptually tricksy, I'll work my way up to its full glory by going through four versions:
- make a lens compatible with
Deeply.get_all
. - make one compatible with
Deeply.update
. - combine the two into a lens function that works with both.
- add compatibility with
Access
(so lenses work withget_in
,update_in
, and friends).
Then I'll show how this understanding can be used to debug a couple of lenses that have surprising behavior in pipelines.
Finally, I'll describe the implementations of some interesting makers, so that you can pattern your own makers off them, should you want your own makers.