Functional lenses for C++14

This post is about one more functional programming idea – LENSES. As you could guess it could be implemented using modern C++.

funtional lenses

Concept of lenses from functional programming is actually pretty simple – lens is just pair of getter and setter, which are separated from target object. The main power of lenses is that you could combine them into chain to save a lot of work when you access or modify parts of complex nested structures. The analogy is the following – you can’t get much profit from one lens, but if you combine the bunch of lenses you could make telescope or microscope, etc.

Also there is a big profit when you work with immutable data. In that case a setter is a function which creates a copy of object with modified part. To modify nested structure you could produce very large piece of boilerplate code. But as you will see the lenses could solve this problem brilliantly.

LENS

So a lens is just a pair of functions (getter and setter):

Getter(Object) -> Field      +      Setter(Object, NewField) -> NewObject

There are several ways to express this using C++ – there is nice presentation here: slides . Another implementation could be found on github – link.  And to finish the list there is nice post at Bartosz’s programming cafe – link.

Here is my draft implementation and couple of examples.

To construct a lens we could use the following builder:

As example of immutable data let’s grab the example from previous post – about the way to create immutable structures in C++11:

This structure represents some event which has a name, rating, some schedule of time intervals and some integer tags. Let’s start with trivial lens created manually – accessor for title field of event.

Note: we even created object after the lens.

We could insert constructors for such trivial lenses inside main macro which performs immutability magic! So instead of boilerplate creation of lenses we just need to call static method of immutable class:

So all lens-constructors for basic fields (in current example: isPublic, title, rating, start, finish, etc) are generated automatically.

COMPOSITION

lenses

Ok, now main magic – composition of lenses. To make such composition we could make special function (call it zoom for example), or we could use infix operator like the one inside slides. Or we could just use piping again to compose things (post about piping) – so we only need to overload “|” operator.

Simple!

Let’s imagine we need to modify start time of one item inside our event’s schedule. There is the obvious problem – how to deal with arrays? To solve this we need custom lens which work with lists and focus on specific element of the list. The obvious lens might focus on element inside given vector by index, but to make this more error-proof we could focus on item by id. For example:

I used functional syntax here, but it could be easily rewritten using any regular syntax as you might guess. So consider it as just as example how it might look.

Now we are ready for final example:

We form final lens in one line and then apply it to correct schedule item with id = 1. This could be extended to any kind of complex nested immutable structures. Also you could create any custom lenses as we did to access vector element. It could even have some inner state.

Any way – lenses are brilliant way to modify parts of serious immutable data.

OUT OF FOCUS

There is one minor problem which you probably had experienced when tried to make some photos – sometimes you can’t get object part into focus. The same thing will happen if in previous example you will try to modify schedule item using wrong id. If such id does not exists inside schedule whole chain of lenses will crash. Let’s invent some protection for such case.

Modern camera will not shoot if autofocus system is not locked on something – so let’s add method bool hasFocus(…) to lens. I added this as third must-have parameter to lens constructor but there are probably many other ways.

So lens_item_by_id() and composition operator will be modified accordingly:

Now every lenses composition could be checked before run:

Here we tried to focus on element with id 10, which was not in the list. If we provide other object which contains such schedule item – the lens will get focus.

This is nice way to avoid a lot of nullptr checks in real cases.

Focus check could be also implemented through some monadic execution of such chain, but this is another topic.

ADAPTIVE OPTICS

Instead of providing a variable to lens constructor we could use a function as predicate parameter. This functional parameter even could be a mutable function or some external dependence.

For example we could write generic find method as lens:

And use it in the same scheme:

Method hasFocus here could still be used to get rid of nullptr checks and in some cases this could be used as solution to replace MayBe monad (for a price – we need to traverse the chain twice). Also we could extend lens with additional parameters in both get/set methods and constructors and get more complex designs.

CONCLUSION

  • Lenses are nice way to write access/modifications of complex structures.
  • They have a lot of flexibility to tune.
  • Auto generation of lens-constructors for basic immutable fields could save a lot of time.
  • Separation of accessors / modifiers / data is a way to simplicity.
  • Functional pipelines are suitable way to construct composition of lenses.
  • Additional method to check focus could replace nullptr checks.
  • Introducing functional parameters to lens constructors gives additional flexibility.