-
-
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
PR: Function composition and negation (a.k.a. "It's like a category, man!") #17119
Conversation
Oh, and the other "interesting" feature is an ability to perform splatting, using the The alternative was to implement a separate, splatting composition. Although this is a great idea, I tried it and I found it to be more confusing to use and much less clean than the current implementation. To make it easily usable, yet another unicode symbol would be needed, or alternatively take over some syntax like:
|
I think I'd be ok with this without the splatting and the functor parts. Of course, that boils down to about two definitions: ∘(f, g) = (x...)->f(g(x...))
!(f::Function) = (x...)->!f(x...) |
Hmm, yes, I see your point! And thanks for the review. Indeed, the ugliest part was Regarding functors - is this a "less is more" approach to I'm still planning on overloading
which I thought was particularly beautiful for a programming language. (You obviously loose this, and similar abilities, with anonymous functions). But there is no reason packages outside of Final question, would you include the ASCII alternative |
See the discussion of #5571 (Which is the currently 14th most commented julia issue of all time). Also, for SISO functions, this composition syntax, is arguebaly plain better than the pipelining syntax. Consider the equivalents, when actually evaluated at a point
|
Thanks @oxinabox for reminding me of #5571. I just put in my two cents there #5571 (comment). I guess what I like about |
I have a macro to do this in ChainMap.jl, |
Yes indeed! Whoever merges this can choose "merge and squash." I would have recommended making a PR from a feature branch rather than master though. Next time 😄 Nice ideas here by the way, I've been wanting |
Here's the minimal alternative: #17155. Maybe not desirable since it may make using |
Cool, Stefan. I actually have those lines plus docstrings and tests on my laptop, but unfortunately I wasn't able to post them before the long flight to Australia. And now I'm swimming in children and dead tired, so I might get around to adding them later.
In my docstrings, I described I don't know - would you want more complex behavior in Base? I sort of see its role as providing semantic consistency among the language's users, and IMO "functionally equivalent" is good enough for that. |
Moved to #17184 |
This PR allows the ability to compose functions with
compose()
or the∘
operator, so that(f ∘ g)(x) = f(g(x))
. Furthermore,!
applied to functions is converted to a composition, so!f == ! ∘ f
. This enables the syntax sought by @JeffBezanson, where we can write e.g.map(!isless, a, b)
instead of explicitly introducing an anonymous function,map((i,j) -> !isless(i,j), a, b)
.The composed functions or functors are stored by default in a functor of type
ComposedFunctor
instead of an anonymous function, and I'm also defining the interface (in the docstrings) to make it acceptable to intercept this. The reason for this is that we can (optionally) then introspect the structure of the composition to apply intelligent optimizations and transformations. As a simple example, we can define that(! ∘ !)(x::Bool) = x
, which should already be done by LLVM. A more complex example would be taking a series of dataframes/database/SQL commands and transforming them to the most efficient form before extracting data and computing the result.Finally, we also define
inv(f)
as an interface for defining the inverse of functions/functors. So far, I have only implementedinv(identity) = identity
, but this is useful interface to use in packages (discussions about domain issues in things likeinv(sin) == asin
can/should be done separately to this PR). In particular, our CoordinateTransformations.jl package already uses this extensively and it is extremely useful (and well-defined).PS - this is my first PR to Julia, and I don't know how to do squashing on GitHub (I read it is available when the PR is merged). Please let me know if I've done something else wrong.
PPS - thanks for JuliaCon 2016!!