-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change lens-view* #89
Conversation
What? Why would you change lens-view to do that instead? |
It's not supposed to do that, it's supposed to be a nested reference. |
And that's consistent with |
Nothing to do with mapping over a list. This makes it inconsistent. |
So it obeys the lens laws when paired with > (lens-view* '(a b c d) first-lens third-lens)
'(a c)
> (lens-set* '(a b c d) first-lens 'a third-lens 'c)
'(a b c d) That is, setting what you just viewed does nothing. This isn't the case with the old definition of |
No it doesn't. |
|
What do you mean it follows the lens laws? I thought the lens laws were about how lenses were supposed to be constructed. |
The updates were one after the other, but they were independent and each lens had the same domain of target values. It wouldn't matter what order you did them in (as long as you didn't update the same thing twice). For |
Except the order does (and should, according to the lens laws) matter for |
The lens laws are about how lenses are supposed to behave with respect to |
Because if you do something like (lens-set* '(a b c) first-lens '(1 2 3) (lens-thrush first-lens second-lens) "two") |
Also, |
In that case, the second lens is still viewing the full target, it's view just happens to collide with the view of the first lens. For (lens-set* '(a b c) first-lens '(1 2 3) second-lens "two") where later lenses view what was set by earlier lenses. That would be useful and should definitely be provided, but provided separately. |
That's also something that |
Yes but I think it's more confusing and less useful (in reply to your last comment). |
It's even more confusing to have one pair of viewing and setting functions that obey strict laws and another that don't. One of the big advantages of lenses over mutation or raw getters and setters is that the laws make it easy to reason about lenses and derive important properties from them. |
But now |
It would be better to rename your variant |
Because your |
There are multiple ways to generalize viewing and setting. And yes, this definition of viewing and setting should be renamed, but it should be renamed along with set* and transform* because together they obey the lens laws with respect to plural views and plural lenses. |
No they don't, really, because the plural set and transform functions do not behave like a |
Plus |
If you wanted a |
But I just realized we were talking about different kinds of nesting. You have been talking about nesting as in going further into nested data structures, whereas I was talking about nesting as in nested function calls, syntactically. Is that right? |
Re what they all previously did: Yes, with the exception of Re nesting: Yes, we have been talking about different kinds of nesting. For what you're talking about, yes some sort of lens-set/thrush which dealt with singular views and targets and plural lenses would be great, but in order to obey the laws |
Also, |
That's a good point. So in addition to the above, it should be the case that:
And that:
That should probably be the formal definition of this behavior extension. |
And that's the syntactic nesting, not going deeper into the data structure. |
Precisely. I think the semantic consistency is more important than the syntactic consistency, but it would be nice to have both. |
Except that the |
Ok. I just realized something. |
If you want a "consistent" set of functions, they should all be "plural" in the same way. |
But if you make a new set of functions that follow the previous (lens-view** target lens ...) = (lens-view (lens-thrush lens ...) target)
(lens-set** target lens ... #:-> view) = (lens-set (lens-thrush lens ...) target view)
;; yay! keyword arguments solve the rest argument issue!
(lens-transform** target lens ... #:-> transformer) = (lens-transform (lens-thrush lens ...) target transformer) And that's the consistent set of functions that the previous |
Ok. So you're right. That's not where the previous |
And by the same "plurality" argument, the |
Yes that's exactly it. This current family of variations should be named something else though. Maybe (lens-view/list target lens ...) == (lens-view target (compound-list-lens lens ...))
(lens-set/list target lens view ... ...) == (lens-set target (compound-list-lens lens ...) view ...) This wouldn't quite hold for transformations however due to the property that later transformation functions see the results of earlier ones. As for the new family of variations, they could be named to imply composition due to their relationships with |
Ok. |
Well if you follow this reasoning, then a lot of them end up producing lists, for the boring way of defining these anyway:
|
A lot of them do, yeah. I think in the singular cases the way you get interesting behavior is usually by making a new lens. |
But I feel like most of the ones that just produce |
I definitely don't think we should add any of them just to add them. The plurality principles are more just something to keep in mind when we come across a useful extension to viewing and setting. |
Actually, given this, it seems like the new (lens-view** target lens ...)
= (list (lens-view lens target) ...)
(lens-set** target (~seq lens view) ...)
= (list (lens-set lens target view) ...)
(lens-transform** target (~seq lens transformer) ...)
= (list (lens-transform lens target transformer) ...) Even though the last two return multiple targets (they all consume one target), because they all have the same |
All three a family should share the same plurality as a rule, because I don't think it would be possible or useful to extend the lens laws to a view/set pair where the two have different pluralities. Consistency with the laws supersedes shared behavior - if the behavior can't be common across a set of functions without breaking the laws, they should probably be separately-named functions. |
Re: the |
Yes. However while symbols are easier to read once you're familiar with them, words are easier to read when you're learning them. My point-free package provides the symbol |
Ok, but |
Using slightly different symbols for the same meaning would affect readability, and I'd rather optimize for readability than keystrokes. |
Yes, but that's in a different package, so readability for this package shouldn't be affected by some other package that "happens" to provide a useful function for a very similar concept, even if that happened to inspire this. Racket programmers are used to typing dashes in between words, and this would be a dash after a word, and to typing |
It's not just a similar concept though, it's the exact same concept. And if you're the type who prefers that argument order, you're likely to have the other package as well. Additionally searching for this concept usually lands at Greg Hendershott's threading macro blog post which sets a strong precedent for |
Yes, but only because |
Closes #88, connects to #80 by making it unblock 1.0