lens icon indicating copy to clipboard operation
lens copied to clipboard

lens-join/* functions produce non-lenses when views overlap

Open lexi-lambda opened this issue 8 years ago • 2 comments

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.

lexi-lambda avatar Nov 27 '17 06:11 lexi-lambda

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)

AlexKnauth avatar Nov 27 '17 17:11 AlexKnauth

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
...

AlexKnauth avatar Nov 27 '17 17:11 AlexKnauth