Skip to content
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

Argument orders of lens functions should follow some formal convention #73

Closed
jackfirth opened this issue Jul 7, 2015 · 35 comments
Closed
Labels

Comments

@jackfirth
Copy link
Owner

See #72 for the discussion that prompted this issue

UPDATE

The argument order conventions are, in order of decreasing priority, as follows:

  1. Singular arguments before variadic arguments.
  2. Plural arguments should be expressed as variadic arguments.
  3. Twice-plural functions must take their plural arguments in one-to-one correspondence and should take them as a series of pairs in variadic arguments
  4. Lens arguments before target arguments before view arguments.
  5. transform functions should follow the same conventions with their transformer arguments taking the place of view arguments.
@jackfirth
Copy link
Owner Author

I don't think any variable-arity functions should contain singular items in the rest arguments. Something with the signature (f x y ... z) should be (f x z y ...) instead.

@AlexKnauth
Copy link
Collaborator

And that's another part of why I chose the version of lens-set* that I did.
(Edit: see #72 (comment))

@jackfirth
Copy link
Owner Author

Yeah, that makes sense.

@jackfirth
Copy link
Owner Author

There's some important different shades of possible plurality that are worth noting:

  1. Only one of lenses, views, or targets is plural. This one seems easy enough - in keeping with varargs last, move the plural item to the rest args.
  2. Two of lenses, views, or targets is plural and they're in one-to-one correspondence, such as lens-transform*. Also in keeping with varargs last, I think in this case the two plural items should be last but preserve the same relative order. first singular lens, view, or target, then plural pairs of of the other two in the same order (lens - view, lens - target, or target - view).
  3. Two of lenses, views, or targets is plural and they're not in one-to-one correspondence. There are no functions that behave like this, a possibility might be something like lens-view* that works with multiple targets and is equivalent to mapping lens-view* over each target. I'm not sure what to do about this case, or if we should just make a hard rule not to provide functions like this.
  4. All three are plural. This is madness.

@AlexKnauth
Copy link
Collaborator

In general, do you want the lens before the target, or the target before the lens?

Lens before target makes if feel more prefix-y and consistent with function application, while target before lens makes it feel more postfix-y and consistent with functions like hash-ref.

@jackfirth
Copy link
Owner Author

I think of lenses as abstractions over certain kinds of functions rather than keys or indices to data structures, and I think positioning them first is more in keeping with that feel. What do you think?

@jackfirth
Copy link
Owner Author

The view should in general go last (exempting plurality exceptions) since it's not given in both lens-view and lens-set

@AlexKnauth
Copy link
Collaborator

Re: lens-target vs. target-lens:
I think lenses make perfect sense as both functions and as keys to data structures, and I like both the prefix-y and postfix-y styles.

But in terms of consistency the postfix-y style seems better to me because it's more consistent with the plural forms with multiple lenses, where they should come last.

@jackfirth
Copy link
Owner Author

There's also the plural form with multiple targets and a single lens to consider. The other big problem is that although backwards compatibility isn't committed to yet, lens-view, and lens-set have remained completely compatible since their creation and form the core of most lens operations, so I'm hesitant to break them.

@AlexKnauth
Copy link
Collaborator

Yes.

@AlexKnauth
Copy link
Collaborator

What would a plural form with multiple targets and a singular lens look like?

@AlexKnauth
Copy link
Collaborator

(map (lens-view lens _) targets) and (map (lens-set lens _ _) targets views), maybe?

@jackfirth
Copy link
Owner Author

Yes that's just what I was thinking

@AlexKnauth
Copy link
Collaborator

Are those as useful?

@jackfirth
Copy link
Owner Author

They'd just be shorthands, but that would be the case with many of these plural functions like lens-view*.

@AlexKnauth
Copy link
Collaborator

But not really for lens-set* or lens-transform*, though.

@jackfirth
Copy link
Owner Author

There could also be a version that instead of taking one new view for each target in the set takes a single view and sets each target to the same view.

@jackfirth
Copy link
Owner Author

lens-set* and lens-transform* are more complex, but both are essentially shorthands for a longer for/fold with (in-slice 2)

@AlexKnauth
Copy link
Collaborator

(map (curry lens-set* target) lenses views), maybe?

@jackfirth
Copy link
Owner Author

Yes. Given all this, I personally am in favor of lens-target-view for the function-application feel and the backwards compatibility. What do you think?

@AlexKnauth
Copy link
Collaborator

And what about the value of keeping the lens and the view next to each other?

@jackfirth
Copy link
Owner Author

I'm not certain of the value of that because when not doing any setting or updating there isn't a view anyway.

@AlexKnauth
Copy link
Collaborator

What if you were doing this:

(lens-transform lens (some-really-complicated-target-expression-that-takes-up-space-and-requires-a-little-bit-of-thought) (lambda (val) ...))

Wait, where is this value going again?

@jackfirth
Copy link
Owner Author

In that case I would probably advocate for a define or let pulling out the complex expression

@AlexKnauth
Copy link
Collaborator

That works, and that's probably what I'd do anyway, but it would be better if it weren't necessary. lets can get in the way sometimes.

@jackfirth
Copy link
Owner Author

For what it's worth, foldl and foldr have the same problem with a complex initial value expression. I think in general complex expressions can mess up everything and the best approach to dealing with that is to very strongly advise against complex expressions and make useful helpers and shorthands.

@jackfirth
Copy link
Owner Author

And yeah, lets are somewhat verbose. The Racket style guide advocates using defines over lets. Unfortunately that doesn't help as much in expression contexts.

@jackfirth
Copy link
Owner Author

Last thought - lens-first cooperates better with curry, as it makes it easier to write things like this:

(define set-first-of-second (curry lens-set (lens-compose first-lens second-lens)))

@AlexKnauth
Copy link
Collaborator

But also, target-first cooperates better with curry if you want to map that over a list of lenses, so there's two sides to that as well.

@jackfirth
Copy link
Owner Author

Yeah. I'm not sure arguments about partial application or which two parameters are next to each other really provide support one way or the other, because either way there's counterexamples for the other case.

@AlexKnauth
Copy link
Collaborator

And the "function" argument works both ways too, if you like things like ~> from rackjure or point-free.

@jackfirth
Copy link
Owner Author

That it does. I don't think the reasons for target-first are compelling enough to justify the backwards incompatibility. Therefore, I'm going to mark the following conventions as final, in order of priority:

  1. Singular arguments before variadic arguments.
  2. Plural arguments should be expressed as variadic arguments.
  3. Twice-plural functions must take their plural arguments in one-to-one correspondence and should take them as a series of pairs in variadic arguments
  4. Lens arguments before target arguments before view arguments.

Any last thoughts?

@jackfirth
Copy link
Owner Author

Ah yes, last thought - in the case of lens-transform and friends, the signature should follow the same rules as lens-set with the transformer arguments taking the place of the view arguments.

@AlexKnauth
Copy link
Collaborator

Ok.

@jackfirth
Copy link
Owner Author

Closing this issue now, as all provided exports currently follow this conventions. This no longer blocks 1.0.

@jackfirth jackfirth removed this from the 1.0 milestone Jul 8, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants