-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Make higher-order functions composable #33027
Conversation
Huh. This is cool and so simple I'm surprised that no one has proposed it before. |
I would want to have a better notion of the scope of this: where do we stop? With a clear answer to that, I would be pretty happy with this. |
This scares me. |
Hence my request for a notion of the scope of these changes. For example with the |
there was a discussion on slack for this. Given the frightened comments, one heuristic to stop would be to apply this to functions with signatures For sure, we can keep composing the result of a |
With this scope, this does not apply to many other functions, most (HO) functions I am trying to find either:
|
Another example that would work for this case but isn't implemented in base would be |
Wouldn’t chaining be just as powerful and more flexible? The LightQuery syntax would be xs = rand(50) |
And for super lazy powers just use Base.Generator and Iterators.filter instead |
This seems like the slowest possible way to compose transformations; adding this just encourages people to write slow, unreadable, surprising, hard-to-reason-about code. One of the things I've appreciated about Julia over the years was that it didn't have this kind of thing, where you forget an argument to the method and suddenly your result is an anonymous function. And what if you want to compose higher order functions based on a different argument? It seems weird to decide that one particular argument of one particular method is The Blessed One which when omitted gives you a function. |
Why would this be particularly slow? |
Lots of anonymous functions and it tempts people to write things as in the OP, e.g. |
Fair point about the temporary arrays. I don't think the anonymous functions are so bad though. |
The temporary arrays are not problem if you do this only for functions in By the way, another nice thing is that ixf = map(string) ∘ map(x -> 2x) ∘ filter(>(0.5))
ixf(xs) The "iterator transform" |
This came up in a conversation on The temporary allocation of arrays depends on the type of array being fed in. |
Aren't transducers the way to compose functions like |
@andyferris Transducers and iterator transforms (:= curried version of "iterator factories" like At this point, I cannot help mentioning that transducers are "adjoint" of iterator transforms (Thanks to @jw3126 who figured it out. See also my slides 32 and 33 of JuliaCon). That is to say, if map(string) ∘ map(x -> 2x) ∘ filter(>(0.5)) # iterator transform
Filter(>(0.5)) ∘ Map(x -> 2x) ∘ Map(string) # transducers (this is like So, to convert iterator transforms to transducers, we can just map an iterator transform (e.g., Going back to the original point, I think defining |
I guess this should be closed, following the discussion that followed (thanks everyone). |
This proposal allows the direct composition of higher-order functions, starting with map and filter.
This is especially convenient with the piping syntax: