-
Notifications
You must be signed in to change notification settings - Fork 1
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.prototype.compose #1
Comments
Compiler support to do some sort of code fusion or stack frame reuse would be helpful for deep function composition trees. |
My immediate thought was that this is duplication of fantasyland/function-prototype-map#1, although, as you said, it's the same implementation for two different things, so 🤷♂️ Maybe To port my concern over from that issue, both you and @safareli mentioned variadic arguments. In either That said, it's working for Ramda, so maybe I'm just stubborn 🙃 Either way, both proposals are a move in the right direction. My only concern, as I said, is the misuse of meaningful terms; I'd almost be tempted to push for |
This was my point in the "Static method?" section. I think a variadic static method is more likely to get traction. I would argue that the
Agreed. I think a static method is more appropriate in this case. |
See https://gist.github.com/isiahmeadows/7b5b49469c08bd3ddc425d15b0bd65c8 for an operator based approach |
Just discovered mentions don't notify from gists so... |
I'd personally prefer a new language operator over a method (conciseness, zero-cost), but I'd take either provided the engine is smart enough to optimize it. I haven't had the time to really push for significant feedback yet, though. Probably should move it to a repo soon. Edit: proposal now lives here. |
My bias is in the other direction (method), but I'd be happy with one of them making it into the spec. An operator only wins on conciseness for short composition chains: pipe(f, g, h, i);
// vs
f >:> g >:> h >:> i But if the compiler can't be convinced to optimize the method variant, I'll take an operator. |
@gabejohnson Either one could be optimized well. Just the operator version could result in optimized bytecode. And yes, it is slightly more verbose, but the operator choice really could stand to be improved (ideas welcome). |
Deleted the last two comments and moved them to dead-claudia/lifted-pipeline-proposal#1 |
On the "arity of composing functions" section, I'd like to bring up this example: //+ map :: Functor f => (a -> b) -> f a -> f b
const map = f => xs => xs.map(f)
//+ prop :: String -> StrMap a -> a
const prop = k => sm => sm[k]
//+ compose :: (b -> c) -> (a -> b) -> a -> c
const compose = f => g => x => f(g(x))
//+ pluck :: String -> [StrMap a] -> [a]
const pluck = compose(map)(prop) With Haskell-style unary currying, this is exactly as much code as is needed to do this. Any binary operation can be lifted to operate on an array by applying it to Even more magic is lost if any function can have any number of args, as
The first option of the second point seems sensible to me, because then it does give us ways to massage the spec into something useful. Thus, a potential (untested) implementation (thanks, @stoeffel) would probably be something like this:
The beauty of this is that it doesn't actually break any unary function code, but nor does it require that behaviour. So, we (as FP library contributors) are free to place that restriction at a higher level :) |
@i-am-tom I invite you to check out my proposal linked earlier in this bug. I've actually thought out several parts of this already. |
Apologies; missed the link! The concept of an operator frightens me because, in all other situations, the compiler can be quite rigorous: does an Also, as someone who isn't a huge fan of |
It can statically determine and perform after type checking the following with minimal effort:
It'd likely end up just |
Interesting! Is that only-one-argument restriction disereable? Thinking about cases like I like the syntax ideas, too! Have yourself an upvote ready when you are :) ✨ |
Re: https://gitter.im/sanctuary-js/sanctuary?at=596e241b329651f46e9c5830 I think we should try proposing a variadic I think an on ramp for that conversation sticking is to get some kind of higher order function composition in the language with a simple proposal where we aren't going to be too bothered when they inevitably want it to become convenient. It's easy to polyfill, implement, it exists in lots of popular libraries just like this proposal, but we won't get into the dreaded ivory tower vs pragmatic debate if we are proposing a function that isn't required to be lawful. Getting one proposal over the line could be very useful when making future proposals. |
I do feel that it might be better to propose both simultaneously with their downsides, to see which TC39 would prefer. They honestly could go either way. Syntactic compositionPros:
Cons:
New
|
This seems like a no-brainer. However, there're some things to consider:
Argument order
The newly introduced Semigroupoid specification gives an argument order of
g.compose(f)
. I think this is fine. Dispatching functions (Ramda, Sanctuary, etc.) will flip the order anyway.Static method?
Another possibility is to put this functionality on the
Function
objectGiven the long-time variadic bent, I would expect (with my "pragmatic" JS dev hat on) to be able to pass
n
arguments toFunction.compose
Arity of composed functions
My thinking is
compose
is a binary method as laid out in the spec. See (2).Arity of composing functions
The obvious answer is
1
. Another possibility isn
for the first applied function and1
for the rest. A counter-intuitive option is to have no restriction. This would prevent future incompatibility. Imagine a nativeTuple
type and a future whereThe above allows for an unrealistically FP friendly future, but I don't see the immediate requirement for an arity restriction (save "type" checking). Having such a restriction would rule out this possibility.
Edit: relabel/reorder section headings
Edit: "Static function?" -> "Static method?"
Edit: Remove "obviously"
The text was updated successfully, but these errors were encountered: