Context: Someone posted this article to reddit and a number of people found it difficult to see the goal and meaning of Lenses.

There are a number of comments pointing out, basically, “But why all this??”.

I think it is a fair question. I also think the answer is not “No reason; this is all pointless”. Finally, I do think that the original article makes a bad attempt at answering this by condensing it all in just one sentence.

In short, they are functional getter/setter. A short hand functionality for accessing as well as updating data objects.

Not that the explanation is wrong, of course, but it is too terse and requires quite a bit of effort precisely from those to who the article is apparently directed. This being “an introduction” it should make much more of an effort at explaining the whys.

So, anyway, why all this? (Or “what does functional getter/setter mean and imply?”)

Let's remember, as a starting point, how the comparison FP ↔ OOP is sometimes described as a matter of designing with verbs vs designing with nouns. Of course we know this is not mutually exclusive (as are not FP and OOP), but each approach does tend to favour one over the other.

Why does this matter? It matters because FP leans towards verbs. And this makes FP proponents seek ways that favour using verbs. Given that, objects (nouns) tend to turn mostly into records. The word is used for a reason, to signify that they are “merely” records, that it's data (as opposed to logic). Keep this idea in mind because it means that that logic will have to reside elsewhere.

In FP this elsewhere is of course functions (verbs). FP favours thinking about doingStuffTo(aThing) rather than having aThing.beStuffed(). Not only that, OOP will tend to use objects to produce other objects as a way of defining process, while FP will tend to compose functions into other functions as its way to define process. So, naturally, FP wants to have all the logic it can in functions. Meanwhile OOP wants to have all the logic it can in objects. ( Broadly speaking here :) )

Now one particular sort of logic that objects “frequently” contain is getters and setters. It is a simple form of logic but Accessors are widely used to provide a number of desirable properties by holding some particular type of logic. Mainly it can all be reduced to their name: they hold the way to control and manage access to the object's actual data.

Brief interruption: Yes, I know in JavaScript-land, accessors are apparently not as common as in other languages. This is probably because we've long been accustomed to the idea that you either make things public, use closures to generate some form of privacy, or use a crappy _convention and cross your fingers hoping other people respect it. But there's two things to think about. One is that, as the original article actually shows (or at least hints at), simply accessing obj.prop is indeed a form of accessor - a simple, transparent, no-control accessor. The other is that of course, since some time ago you can define actual accessors. In any case, remember to think about obj.prop = 7 and a = obj.prop as accessors, please. It may become relevant later on.

Ok, then. There's one other thing that accessors provide that is not totally related to controlling access in the sense of restricting that access. And it is a most desirable thing for FP. Accessors wrap access to data in functions.

Think about that carefully because it's the key to all this. Lenses are, in fact, the way that you wrap access to some record's data into a function (or a pair of functions if you want to be precise). So, essentially, what we want to do is simply wrapping…

obj.setProp(...); // Or simply obj.prop = ...
// and
... = obj.getProp(); // Or simply ... = obj.prop;

…into functions. Why we want to do this is clear, if you see it from the FP perspective: We want all logic in functions so that we can compose it. Let's imagine we have something like…

// print, sumOne, and double are functions

…With this, the FP approach would suggest composing all three functions and then applying it to the data. So one would…

// Say something like compose = (f,g,h) => { return (x) => f(g(h(x))); };
const process = compose(print, sumOne, double);

Right. But now, let's imagine we have a slightly different process…


…Hmm. We could just ignore that. We could just tell ourselves that we're fine just composing print, sumOne and double as before and leaving the extraction of number from obj aside…


…and things are mostly ok. But the thing is we've been talking about how accessors wrap the logic of access to a record's data. And we could have some logic in that accessor. But even just deciding that the property to get is number is in itself some form of logic. So it nags us somewhat. (Ok, maybe it doesn't nag you xD But it nags a FP proponent somewhere ;) ).

So the solution is obvious: We wrap that access logic into a function and compose that into the process.

Here, though, the original article -IMHO, of course- fails somewhat by opting on using Ramda's prop and assoc functions without further explanation, assuming the reader knows them and knows them very well. I would actually say an “introduction” probably shouldn't make that assumption and in this particular point the article really fails to provide the promised introduction by requiring knowledge that is actually quite close to what it is supposed to explain. Also it's bad because in fact, those two are two very simple functions that would take little space and time to present and actually seeing what they do, helps a fair amount.

As you can see, Ramda's prop does nothing more than return obj[prop];. And Ramda's assoc does little more than obj[prop] = value; ( Yes, it does do a little more: respecting immutability, assoc creates a new object instead of mutating the passed one. - Yes, /u/ggolemg2, Ramda's assoc does exactly what you said; look at the linked source above :) ). Ok, let's assume that we have prop. Now we can actually compose all of the process…

// const prop = (name) => { return (obj) => obj[name]; };
const fullProcess = compose(print, sumOne, double, prop('number'));

So, now that we know why we would want functional getters / setters, what are lenses? You can think of lenses as a construct that simply combines the getter and the setter to one specific piece of an object/record. ( The name, lens, comes from the fact that it focuses on one part, in case you hadn't noticed. It took me some time to realize this ^_^u ) They are sometimes called “purely functional references (to an object's data)” because they are actually a bit more generalized than “getter + setter”. The idea is the same but on the more general idea of access (which can take the form of an array's index, for example).

In any case, whether you stop at the simple idea of “getters/setters” or take on the more general concept of “access” as “references”, the answer to the question at the beginning is the same. Why would we want all this? So that we can wrap access logic into a function so that we can compose it with other functions to build bigger processes. And we want that because composition is how FP approaches building things. (You can, of course, decide you don't really want to do FP at this level, and then all this would indeed be pointless for you. That's fair; to each their own, they say, right?)