-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Application and binding/currying operators #1520
Comments
I think a currying operator would be sweet. Not so much a function application operator, since function application is implicit anyway (except for zero-argument calls, but we have postfix- Also, it's been discussed many times before, but we just can't have both edit: Oh, though your function application operator is left-associative and the implicit function application is not. That does make the complex nested calls more readable... |
For the record: We used to have |
@jashkenas, it looks like it was removed after #251 -- I'm not clear on the reasoning (as you stated then, Alternate syntax for curry: Mnemonic:
|
The reasoning is that We removed it after auditing some real-world CoffeeScript code, and determining that it was barely ever needed. |
@jashkenas: I don't know how reliable an audit like that would be. I write very different code when I switch paradigms. In Haskell, a purely functional programming language, I use currying all the time. It's actually made very easy for me because any function given too few arguments produces a curried form of itself. If we had more functional programming facilities, maybe we would see an increased use of that style. But also, maybe not. |
Agreed -- ubiquitous currying makes a ton of sense in a lazily-evaluated language like Haskell. For better or for worse, JavaScript is not lazily evaluated. |
In chronological order... Yeah so the main use of the vanilla application operator would be indentation-as-application as mentioned above. In addition to finessing indented and parameterless calls, it does have a nice kind of symmetry with the currying operator. I'm not too concerned about the glyphs, so feel free to suggest something else... The previous currying operator was before my time, but it looked just like a special case of apply (correct me if I'm wrong)... With the previous operator:
With the proposed operator:
I like the "spy-vs-spy" operator... Currying makes a ton of sense in any functional language, including strictly evaluated ones like ML, Scala, etc. In Scala, currying is explicit just as it would be with this proposal. Along with bind, it kind of bridges the gap between functions that operate on Just to recap, here are some of the anticipated uses of the currying operator: Binding i.e. currying the first argument to
Being able to use methods as normal functions:
And:
Flexibility in defining functions:
As well as the class methods and indentation examples in the original post. |
Partial application with free vars can be defined - by those who want it - as: _ = {}
partial = (func, a...) -> (b...) ->
i = 0
func (for arg in a
if arg == _ then b[i++] else arg)...
# Alternative
_ = undefined
partial = (func, a...) -> (b...) ->
b.reverse()
func (for arg in a then arg ?= b.pop())...
# Usage:
f = (x, y, z) -> x + 2*y + 5*z
g = partial f, _, 1, _
g 3, 5 # => 30
# As the example above
fold = (f, z, xs) ->
z = f(z, x) for x in xs
z
max = partial fold, Math.max, -Infinity, _
max [-10..10] # => 10
# Without free vars
partial = (f, a...) -> (b...) -> f a..., b...
min = partial fold, Math.min, Infinity
show min [-10..10] # => -10 Am I missing something? Isn't this easy and elegant without new operators? |
The same could be said for a number of things in CoffeeScript, for example:
We can also implement
If there was a way to define named functions (and constructors) we could dispense with the class syntax altogether. If there's an argument for adding something to the language, I don't think it's necessarily whether it can be implemented as a library (although that needs to be considered), but whether the sugar makes certain idioms more accessible. I think the operators are a good fit for CoffeeScript because they touch on a range of issues, including: indentation-as-application, left associative application, binding, currying, etc. |
I like opening and closing doors. |
It's a bit quiet today, so here's an update... The behaviour of the application operator So this:
Which used to compile to this:
Now compiles to this:
Which is more consistent with the (unchanged) indented syntax:
In other news, the currying operator
The currying operator has been pointed out as being hard to read (which is definitely true in GitHub font). Currently I'm tossing up between |
I didn't intend to say that keywords make a language more difficult to read; just operators (sigils, glyphs, special characters) and even then only if they are rarely used. What is it called in other languages? Would you have a link to some documentation from another language where its use is explained in more detail? |
Closing as there doesn’t appear to be much interest in this proposal lately. If someone wants to submit a PR it would be considered. |
I've been working on a couple of operators for function application. The branch is available here.
The first operator
<-
applies the function on the left to the arguments on the right.The second operator
<~
is similar except it binds the function on the left and partially applies it to the arguments on the right.Here are a couple of examples:
The implementation of __curry is as follows:
The operators touch on a number of issues including:
The deprecated binding/currying operator
Indentation as application
Parameterless function calls
Avoiding parentheses
Now for the tour...
The operators are left associative:
Complex nested calls can be defined without parentheses:
The following section from src/rewriter.coffee:
Can be written as:
We can use the curry operator to partially apply a function:
The operator will bind if the given function is bound to an object:
We can bind and curry at the same time:
We can bind a function to an arbitrary receiver by currying the first argument to
call
:For example:
The operators can be used anywhere normal function application can be used.
Post-control:
Expression and splat arguments:
As an argument to another function:
Part of the motivation was to have more robust class methods:
As you can see, the operators are quite versatile. I'm currently writing a charting library so I will be able to add more tests and examples in the next week or so.
Cheers, Alex.
The text was updated successfully, but these errors were encountered: