Dart feature idea: Automatic currying of functions (inspired by reason)

142 views
Skip to first unread message

Kasper Peulen

unread,
Nov 8, 2017, 8:12:33 AM11/8/17
to Dart Core Development
I just saw a very interesting feature of Reason.

var
add = (x, y) => x + y; var addFive = add(5); var eleven = addFive(6); var twelve = addFive(7);

In other words, add(2,3) is a shorthand for add(2)(3). This would only work if the parameter that is missing is not optional, because otherwise, it is already defined what the behaviour is, if the parameter is missing.

Lasse R.H. Nielsen

unread,
Nov 8, 2017, 8:51:06 AM11/8/17
to Kasper Peulen, Dart Core Development
The issue here is that it hides errors. If everything is allowed, we can't give good error messages on things that shouldn't work.
Say:
 
var result = tryTheFoo(foo);
if (result == null) {
  alert("NO FOO FOUND!");
}

Now, if tryTheFoo actually takes two arguments, this program will compile without issues and never give an alert.

I'm not against currying, but you have to ask for it explicitly somehow. Maybe syntax like:
 
var addFive = (=>add(5,_));  // explicit hole in the expression extracted as implicit argument list

It's easier for binary operators because you can write:

var addFive = (5+); // implicit hole where the operator requires an expression.

It's harder to generalize because it doesn't have a delimiter like the => arrow above, so it only really works for one operator - it's more like a tear-off than a generalized abstraction mechanism, and who doesn't want a generalized abstraction mechanism? :)

/L




--
You received this message because you are subscribed to the Google Groups "Dart Core Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to core-dev+unsubscribe@dartlang.org.



--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

Alex Tatumizer

unread,
Nov 8, 2017, 9:49:02 AM11/8/17
to Dart Core Development, kasper...@gmail.com
Dart is missing a  functional syntax for operators IMO. There should be something like int.+(2, 2) as synonym for 2+2..

Lasse R.H. Nielsen

unread,
Nov 9, 2017, 3:34:23 AM11/9/17
to Alex Tatumizer, Dart Core Development, kasper...@gmail.com
On Wed, Nov 8, 2017 at 3:49 PM, Alex Tatumizer <tatu...@gmail.com> wrote:
Dart is missing a  functional syntax for operators IMO. There should be something like int.+(2, 2) as synonym for 2+2..

I personally agree. It's not a slam dunk, sadly.
We need a way to tear off constructors, getters/setters and operators. This syntax works for operatos, and constructors (apart from the empty-named one) can use normal dot-syntax, and so can setters, but getters are harder. If we find a new syntax for the getters, we might want to use that for operators too, so if we add `2.+` and `int.+` as instance and static "operator tear-off" syntax, and we also get another syntax, then we have two syntaxes for the same thing, which is a waste of syntactic real-estate. 
So, until we figure out what to do with getter-tearoffs, we likely won't be adding any other similar syntax. If it turns out that short closure syntax, like "=>_.foo" is good enough for getters, then using "2.+" or "int.+" might be a good solution.

(It's never just one thing :)
/L

Alex Tatumizer

unread,
Nov 9, 2017, 11:31:37 AM11/9/17
to Lasse R.H. Nielsen, Dart Core Development, kasper...@gmail.com
Won't it be better if "curry" was just called "curry"? Without cryptic shorthand syntax?
E.g. f.curry(5, "Hello", _, _)
Where f - any function expression or getter or constructor or whatnot


Filipe Morgado

unread,
Nov 9, 2017, 12:03:11 PM11/9/17
to Dart Core Development, l...@google.com, kasper...@gmail.com
I can't imagine a situation where currying is so much better than conventional approaches.

Is it so useful that it's really worth it introducing new syntax and complexity to the language?

If so ... is:
    f.curry(5, "Hello", _, _)
... so much better than:
    (int arg3, int arg4) => f(5, "Hello", arg3, arg4);
(Assuming both return a closure).

Alex Tatumizer

unread,
Nov 9, 2017, 9:33:54 PM11/9/17
to Filipe Morgado, Dart Core Development, Lasse R.H. Nielsen, Kasper Peulen
@Filipe: parameter list can be quite long - especially in case of optional parameters (positional or named). It's just not practical and error-prone to write it all manually (plus, more optional parameters can be added in the later versions, unbeknownst to you)

@Lasse:for more fun, you may consider parametrized curry: f.curry<x,y>(x, y, x*2) - which results in a function of 2 arguments (x and y).
Not sure if there's a whole lot of demand for it, but if we are talking about principles, then the syntax (whatever it is) should be able to incorporate this feature (IMO)


--

Philipp S

unread,
Nov 12, 2017, 10:19:20 PM11/12/17
to Dart Core Development, tatu...@gmail.com, kasper...@gmail.com
We need a way to tear off constructors, getters/setters and operators.
The goal of getter/setter tearoffs is lazy (delayed) property access, right? C++ has this feature, and therefore a syntax for it: references.

This concept could either be copied directly, introducing reference types:
var l = ["hello", "world"];
var& len = l.length; // read/write reference
final& lst = l.last; // read-only reference
The setter would be invoked by applying the assignment operator to the reference variable:
len = 1;
print(lst); // "hello"

Alternatively, you could just borrow the address-of operator `&` to access the getter method:
var l = ["hello", "world"];
int Function() lst = &l.last;
l
.length = 1;
print(lst()); // "hello"
Now, what would be the signature of `&l.length`? `int Function()` or `void Function(int)` or `int Function([int])`?
So maybe use the get/set keywords as prefix operators, instead of `&`?
int Function() getLen = get l.length;
void Function(int) setLen = set l.length;

I'm well aware that pointer arithmetics (and everything that might look like it) is a topic that is discussed with great passion, and I don't want to abuse this thread for a debate about its place in Dart. The point I wanted to make was: I think the problem that is unique to property tearoff is the distinction between getter and setter, which will require unique syntax anyways. Once you solve that, you can treat it as a normal variable/function, and apply established language mechanisms to it. So I'd argue that getter/setter tearoff shouldn't block the other features discussed in this thread :-)

Now bear with me while I give my thoughts about the original topic, currying.
The issue here is that it hides errors. If everything is allowed, we can't give good error messages on things that shouldn't work.
Say:
 
var result = tryTheFoo(foo);
if (result == null) {
  alert("NO FOO FOUND!");
}
Now, if tryTheFoo actually takes two arguments, this program will compile without issues and never give an alert.
What do you think of a "delayed call operator" `{}`? This operator looks like a function call with curly braces, but it always returns a function:
String doTheFoo(int n, String s, bool b) {
 
return "$n $s $b";
}

String Function(String, bool) withFirstArg = doTheFoo{42}; // binds `42` as first argument
print(withFirstArg("is", true));

List Function([int]) constructor = new List{};
Obviously, it suffers from the same problem as the `.call` tearoff of functions (discussed here): `f == f{} == f{}{} == f{}{}{}`

Best regards,
Philipp
Reply all
Reply to author
Forward
0 new messages