-
-
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
Function composition and negation, take 2 #17184
Conversation
287c228
to
992facd
Compare
|>(x, f) = f(x) | ||
|
||
""" | ||
∘(f, g) | ||
f ∘ g |
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.
would need to put the signatures into the RST docs so make docs
populates the docstrings there, see details in contributing.md
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 added .. function:: ∘(f, g)
to base.rst and, although it worked for .. function:: !(f::Function)
, I get the following:
WARNING: missing docs for signature:
∘(f, g)
Is this something to do with unicode operators?
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.
@tkelman (not sure if you'd get auto-pinged or not, here)
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.
Yes, no need to explicitly ping me if I've already commented on this issue. It may be a unicode issue where you might have to explicitly declare unicode operators somewhere for RST/Sphinx (I'm not sure where that is though), or it may have to do with the separate signatures being on multiple lines.
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.
OK, yes it is the latter
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.
That's a little unfortunate though. Infix operators should allow an infix form. Even typing ?<:
in the REPL gives help for <:(T1, T2)
- have you ever seen a single line of Julia code written like that??
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.
At least it shows you that operators are just standard functions (OK, not true for <:
) and that you can add a method using the standard syntax. But we should definitely improve these docstrings by adding the infix forms on the second line at the minimum.
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.
@andyferris did you include the entire signature, i.e.
.. function:: ∘(f, g)
f ∘ g
or just the first line .. function:: ∘(f, g)
? Signature matching requires the entire first code block, not just the first line of it.
992facd
to
bda9052
Compare
How is performance? Does the splatting penalty apply here? Edit: Yikes, it's not good at all. This definition helps a lot:
however it probably slows down |
@TotalVerb Good question! Simple check says |
Indeed, if we can't work around it, then maybe we have to follow @TotalVerb's suggestion until the splatting is fixed. I would suggest generating versions up to |
A functor approach might help with that... define 17 methods globally on calling a |
I don't like calling these "functors", especially since (from the user's perspective) they're not meaningfully different from plain old closures. I guess you mean something like this? I did not get a chance to look at your last PR, but I assume it was a similar approach?
This is basically the same as the autogenerated closure type, but more flexible I suppose. |
Actually, since |
OK, yes, functor is a strange name. I meant exactly the thing your wrote, I agree the I actually don't care if there is a once-off overhead to |
@andyferris What I meant was that my assessment was incorrect, and there is no such cost when creating a composed function, because methods are on the (abstract) closure type. So the performance of a "functor" is equivalent to the performance of a closure. |
Decided to make up to 16 inputs fast, to match MAX_TUPLE_SPLAT. Conveniently, closures also allow for introspection of f and g.
Hmm... its a bit uglier, but we now have no splatting penalty! I just discovered closures let us have access to the two things we are composing, allowing for introspection. Cool! (Closures also seem to be a type of "generated type", in the sense the field names and number depend on how you define them. Super cool!) |
""" | ||
!(f::Function) = (x...)->!f(x...) | ||
function !(f::Function) |
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.
Can't you just define this as ! ∘ f
to avoid repeating the same machinery as above?
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 would like to, and I tried that first, but I got some kind of recursion when I tried to compile Julia. I didn't have time to investigate the cause of that yet, so I just used copy-paste.
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'm pretty sure that's because ! ∘ f
doesn't parse correctly. We probably need (!) ∘ f
. This is a little ugly, which makes me like !f
syntax a little more.
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.
That worked... thanks!
We will probably see this with other operators. This is an argument for even more overloads of operators on functions, as in #17155... it would even suggest doing it for every operator. Not sure if I like that or not though! EDIT: or at least every unary operator, since composition is more complex for binary. |
@@ -55,3 +55,6 @@ let xs = [[i:i+4;] for i in 1:10] | |||
@test max(xs[1:n]...) == [n:n+4;] | |||
end | |||
end | |||
|
|||
@test ((x -> x+1) ∘ (x _> 2x))(5) == 11 |
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.
typo @test ((x -> x+1) ∘ (x -> 2x))(5) == 11
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.
Thanks
@StefanKarpinski @JeffBezanson Where are we on this, and what is the probability of 0.5 inclusion? Between here and #17155, the We could maybe try |
""" | ||
∘(f, g) | ||
|
||
Creates a composition of two functions (or functor objects), such that |
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.
this pr doesn't include functor objects any more, does it?
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.
No, it uses closures. But ∘ accepts functors (any callable) as arguments.
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'll edit it to make it clear.
I noted today a place I wanted to used this: Eager-ifying lazy operations
This would become:
Which is nice. |
Yes, that's right. I quite enjoy using these already in our CoordinateTransformations for similar reasons. You gain a lot of control on how things are done with little user effort. The reason my original PR had a |
closing in favor of #17155 |
Something strange happened to my previous PR #17119, and github closed it.
This is the basic version with just an anonymous function version of
∘
and a definition of function negation. This is quite related to #17155.@StefanKarpinski feel free to just take docstrings and tests (in general - is it better to make a PR to your PR?)