lens
lens copied to clipboard
lens-join/* functions produce non-lenses when views overlap
It’s quite easy to produce a lens with, for example, lens-join/list that is not actually a lens; that is, it does not respect the lens laws. Specifically, the produced lens violates set-get consistency when the views of the sublenses overlap. Here’s an example:
> (let ([l (lens-join/list first-lens first-lens)])
(lens-view l (lens-set l '(a b) '(1 2))))
'(2 2)
This produces '(2 2), but the set-get consistency law demands that it produce '(1 2).
The documentation sort of notes this in the following comment:
If any of the lenses share views, then when setting the later lenses override the earlier ones.
However, I don’t think this is phrased quite scarily enough. I think it should be reworded to make it quite clear that the lens-join/* functions do not produce legal lenses when given lenses with overlapping views.
A (lens-join/list X-piece-lens ...) lens only follows the lens laws when this is true for all X.
(lens-set* X {~seq X-piece-lens (lens-view X-piece-lens X)} ...) = X
(Edit: no, the problem is somewhere else)
But that's not the only condition. It also needs these properties for all sets of X-piece ...:
(lens-view X-piece-lens (lens-set* X {~seq X-piece-lens X-piece} ...)) = X-piece
...