-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add ASCII alias compose
of ∘
#33573
Add ASCII alias compose
of ∘
#33573
Conversation
base/operators.jl
Outdated
@@ -851,10 +852,14 @@ julia> fs = [ | |||
|
|||
julia> ∘(fs...)(3) | |||
3.0 | |||
|
|||
julia> ∘(fs...) === compose(fs...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I admit to be surprised by this property: is it documented or an implementation detail of functions returning anonymous functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm not sure that's the best example. Maybe apply the functions to a set of points and show that they always give the same results instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For union
we don't even bother to use the unicode equivalent in the docstring. I think just repeating the previous example but with compose
would be enough (compose(fs...)(3) ==> 3.0
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rfourquet Thanks for the suggestion. It makes sense. I updated the docstring.
https://github.com/GiovineItalia/Compose.jl/blob/2b561b0f53a81cbf9a4001d721d29880d6e50ebc/src/Compose.jl#L18 ... |
Co-Authored-By: Stefan Karpinski <stefan@karpinski.org>
I think this is a similar situation as the addition of |
👍, I was gonna make the same comment and propose the exact same name :) |
I think |
For those examples, does the composition follow the functional composition law |
All of the examples above can be implemented as functions, and if done so, would satisfy type Lens s a = forall f. Functor f => (a -> f a) -> (s -> f s) A lens maps Given that |
The point we're making is that |
I think |
I think this argument can applied many functions in Base. I listed the examples in OP to motivate that there are distinct cases where using [*] I know DataFrames.jl uses |
Another option would be to just call the alias |
Just as a source of inspiration, quoting Function composition - Wikipedia:
Most of them are using pretty generic word, though. |
The original PR had It seems ok for |
Just to spell this out: if Base starts exporting |
My two cents: it's not really relevant that Gadfly breaks as long as we're OK with it doing What matters is what's the best name for Julia. |
I always think of this as the "composition" operator, so why not call it |
Since we're following semver, this seems like a breaking change. If we call this My vote would be to call it |
@kmsquire I’ve often wondered about semver and Julia. Technically any API addition (new exported symbol or new method on exported generic function) could cause ambiguity and code to break. That leaves the question of what the purpose of semver minor tags is in Julia. Pragmatically in my packages I’ve used minor to indicate new API (including exports) and major for changes or removal of existing APIs. |
SemVer specifies that Software using Semantic Versioning MUST declare a public API. Is it declared that As a side note, I've been also thinking to suggest adding "Always prefer explicit import ( |
Yes, this is correct. Adding exports is allowed in minor versions. Of course, we also have a soft promise not to actually break existing packages (i.e. PkgEval should be clean), so Compse/Gadfly may want to choose a new name if we do go with |
@dpsanders I thought it'd be natural for an operator to be a verb rather than a noun. But maybe not the case? Looking at Base and stdlib, they are all abbreviations like Reflecting this trend would mean that |
It seems to me gadfly's sense of |
We've always been pretty clear on the fact that if you rely on implicit |
I know this issue isn’t exactly about changing Gadfly/Compose but I wonder if it is useful to note that there exists a verb |
@StefanKarpinski On that note I’ve always felt that I’d love a tool that intelligently converts |
I feel like the conciseness of infix |
Triage is slightly against this, but we are ok with calling it |
The main theme of this PR is to provide a canonical verb for composition of morphisms. Was it discussed in the triage? Ideally, I would like to know triage's answer to these questions:
Of course, my opinion on the first point is that it's quite large since there are already at least three independent packages that can use this API (see the OP). For the second point, I note that implicit import is known to be not forward-compatible across minor versions #33573 (comment). Having said that, I note a counter argument, a counter-counter argument, and a counter-counter-counter argument: A counter argument may be that it is possible for each package to define an alias using Setfield: @lens, compose
using Transducers: Map, Filter
compose((@lens _.a), (@lens _.b)) # this looks ok
compose(Map(f), Filter(g)) # why is `compose` usable with transducers? A better way to do this is to define a package module FunctionalBase
"""
compose
An alias of `∘`.
"""
const compose = ∘
end so that the above example with using FunctionalBase: compose
using Setfield: @lens
using Transducers: Map, Filter makes sense. Another benefit is that the docstring shown via tl;dr As I think per-package alias or an alias in a shared base package would work reasonably well, I'm going to close this PR. Thanks a lot for the discussion! |
I think this makes sense when For example, in |
Agreed - seeing the structure of the computations can be super useful for a variety of optimizations. |
There are quite a few cases where composition becomes/can be used as fundamental API in Julia:
However, the composition operator
∘
is only exposed by a non-ASCII name. This is not an ideal situation because the common practice in Julia is to provide ASCII-based API even when non-ASCII names are the primary API. An easy solution implemented in this PR is to defineconst compose = ∘
inBase
.