www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Lambda syntax, etc

reply bearophile <bearophileHUGS lycos.com> writes:
I've taken a look at the syntax for lambda in other C-like languages.
This is from Functional Java:
http://functionaljava.org/examples#Array.filter

In Functional Java you can write this D syntax:
(int i, int j) { return i % 3 == j; }
as:
{ int i, int j => i % 3 == j }

It's shorter and less cluttered/noisy than the D syntax, and it doesn't require
more type inferencing (but I think you can't put statements there, so it's less
powerful).

With that Java syntax extension you can write:

final Array<Integer> a = array(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64,
6, 79, 42);  
final Array<Integer> b = a.filter({int i => i % 2 == 0});  

In D (with dlibs) it is:

auto a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42];
auto b = a.filter((int i){return !(i % 2);});

With std.algorithm it may be a bit shorter.

In Python:

a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42]
b = [x for x in a if not(i % 2)]


C#2 has lambdas, and C#3 adds closures and more type inferencing, so C#3+
supports the following syntaxes:
(int i) => { return i % 3 == 1; } // C#2
i => i % 3 == 1 // C#3
i => { return i % 3 == 1; } // C#3, with statements too
To define a delegate o delegate closure:
Func<int> foo = i => { return i % 3 == 1; };
Func<int> foo = i => i % 3 == 1;
Func<int> bar = () => 2;
But this isn't allowed:
Func<void> bar = () => 2;


Few comments I have copied relative to C#3:

C# it automatically generates either an anonymous class or an anonymous method
for the closure depending on if the function needs to close over the local
scope or not.<

When such an expression is evaluated, it produces a function-object which can
be called with the arguments implied by the LambdaList, and whose body
expressions have access to all the lexical variables that are visible at that
point. The ones that are outside of the expression, whose bindings were
established before it was created, are captured. This is why the resulting
object is called a LexicalClosure.<

Even when the code uses the closure more than once, the compiler creates only
one instance of the closure. That environment is reused each time.<

Bye, bearophile
Feb 04 2009
next sibling parent reply BCS <none anon.com> writes:
Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter
 
 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition. [...]
 i => i % 3 == 1 // C#3
 
 i => { return i % 3 == 1; } // C#3, with statements too
 
 To define a delegate o delegate closure:
 
 Func<int> foo = i => { return i % 3 == 1; };
 
 Func<int> foo = i => i % 3 == 1;
 
 Func<int> bar = () => 2;
 

Feb 04 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
BCS wrote:
 Hello bearophile,
 
 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Feb 04 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gmclr4$2q30$1 digitalmars.com...
 BCS wrote:
 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei

I would be all for the string-style, *if* things like the following were fixed: int foo1(int i) { /*stuff*/ } void bar(int[] ints) { int foo2(int i) { /*stuff*/ } auto x = ints.map!("foo1(a)+foo2(a)")(); }
Feb 04 2009
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Andrei Alexandrescu wrote:
 BCS wrote:
 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei

Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.
Feb 04 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Yigal Chripun" <yigal100 gmail.com> wrote in message 
news:gmd0u8$fg7$1 digitalmars.com...
 Andrei Alexandrescu wrote:
 BCS wrote:
 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei

Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.

Agreed. This is what I had always been ultimately hoping for. I'd be happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: "func(someInt) { |a,b| return a+b; };" ) ).
Feb 04 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Nick,

 "Yigal Chripun" <yigal100 gmail.com> wrote in message
 news:gmd0u8$fg7$1 digitalmars.com...
 
 Andrei Alexandrescu wrote:
 
 BCS wrote:
 
 Hello bearophile,
 
 I've taken a look at the syntax for lambda in other C-like
 languages. This is from Functional Java:
 http://functionaljava.org/examples#Array.filter
 
 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

recognizable code because they all use the same argument names. Andrei

given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.

happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: ) ).

Why use this: "func(someInt) { |a,b| return a+b; };" when you can reuse syntax and get this for the same amount of typeing "func(someInt) (a,b){ return a+b; };"
Feb 04 2009
next sibling parent Yigal Chripun <yigal100 gmail.com> writes:
Bill Baxter wrote:
 On Thu, Feb 5, 2009 at 7:26 AM, BCS<ao pathlink.com>  wrote:
 Reply to Nick,

 "Yigal Chripun"<yigal100 gmail.com>  wrote in message
 news:gmd0u8$fg7$1 digitalmars.com...

 Andrei Alexandrescu wrote:

 BCS wrote:

 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like
 languages. This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j =>  i % 3 == j }

have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

recognizable code because they all use the same argument names. Andrei

given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.

happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: ) ).

"func(someInt) { |a,b| return a+b; };" when you can reuse syntax and get this for the same amount of typeing "func(someInt) (a,b){ return a+b; };"

I was about to say the same thing, but I think Yigal was just mixing two distinct suggestions together: 1) the trailing delegates proposal (aka ruby block) and 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;} --bb

not exactly. the reason why I changed the syntax like that is because of templates. for example: void func(T, int i)(T a, delegate int(int) dg) {...} with your and BCS' proposal the above would be called like so: func!(SomeType, 15)(someVar)(a,b){ return a+b; }; this is less clear, IMO. besides, I really like Ruby's (and before that Smalltalk's) syntax to handle this. <g> to Nick - you mentioned the scoping problem with strings. Personally I *HATE* this use of strings. it has many issues which I already mentioned in previous posts. to specifically address your point - what your looking for is called "Hygienic Macros" - http://en.wikipedia.org/wiki/Hygienic_macros basically you want to control which arguments to your AST macro are evaluated at which scope. This i'd like to see implemented in D when AST macros are added.
Feb 04 2009
prev sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
BCS wrote:
 
 Why use this:
 
 "func(someInt) { |a,b| return a+b; };"
 
 when you can reuse syntax and get this for the same amount of typeing
 
 "func(someInt) (a,b){ return a+b; };"
 
 

While I know the compiler could (should) know the difference easily enough, my eyes want to parse that as a chained call followed bizarrely by a naked block, rather than a block. That said, I've always found blocks to be one of Ruby's niftiest features (I do a fair bit of Ruby hackage on the side), and would love to see something like it in D2. -- Chris Nicholson-Sauls
Feb 05 2009
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 7:26 AM, BCS <ao pathlink.com> wrote:
 Reply to Nick,

 "Yigal Chripun" <yigal100 gmail.com> wrote in message
 news:gmd0u8$fg7$1 digitalmars.com...

 Andrei Alexandrescu wrote:

 BCS wrote:

 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like
 languages. This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }

That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.

recognizable code because they all use the same argument names. Andrei

given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.

happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: ) ).

Why use this: "func(someInt) { |a,b| return a+b; };" when you can reuse syntax and get this for the same amount of typeing "func(someInt) (a,b){ return a+b; };"

I was about to say the same thing, but I think Yigal was just mixing two distinct suggestions together: 1) the trailing delegates proposal (aka ruby block) and 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;} --bb
Feb 04 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Bill,

 I was about to say the same thing, but I think Yigal was just mixing

1) the trailing delegates proposal (aka ruby block) and

I like that
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}

I don't like that One #1 I'd be inclined to requier that the function be defined like
 void DoIt(int delegate(int) dg...)

D laready has this syntax for Typesafe Variadic Functions http://www.digitalmars.com/d/1.0/function.html
Feb 04 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <ao pathlink.com> wrote in message 
news:78ccfa2d39bdc8cb54edb3210678 news.digitalmars.com...
 Reply to Bill,

 I was about to say the same thing, but I think Yigal was just mixing

1) the trailing delegates proposal (aka ruby block) and

I like that

Then we're agreed on that part :)
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}

I don't like that

The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body). For the sake of syntax-consistency I would be perfectly willing to allow (or even require) functions to be defined the same way: int add { |int x, int y| return x+y; } Or: // "func" used to disambiguate between function call and function declaration func add { |int <- int x, int y | return x+y; } Or maybe parens instead of pipes (this is similar to K&R C, isn't it?): int add { (int x, int y) return x+y; } Although I'm sure any of those would be prohibitively unpopular.
 One #1 I'd be inclined to requier that the function be defined like

 void DoIt(int delegate(int) dg...)

D laready has this syntax for Typesafe Variadic Functions http://www.digitalmars.com/d/1.0/function.html

I'm not quite convinced either way on this. For what reasons do you think the function header should be required to indicate "this uses block syntax"? What's wrong with just saying "If the last arg a function takes is a delegate, then that delegate can optionally be specified with block syntax."?
Feb 04 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:gmdtjl$2f4j$1 digitalmars.com...
 // "func" used to disambiguate between function call and function 
 declaration
 func add { |int <- int x, int y |
    return x+y;
 }

This one has the added benefit of making it easy to distinguish between an attribute of the function and an attribute of the function's return value (Although I guess that's not much of an issue with the current versions of D2).
Feb 04 2009
prev sibling parent reply BCS <none anon.com> writes:
Hello Nick,

 One #1 I'd be inclined to requier that the function be defined like
 
 void DoIt(int delegate(int) dg...)
 

http://www.digitalmars.com/d/1.0/function.html

think the function header should be required to indicate "this uses block syntax"? What's wrong with just saying "If the last arg a function takes is a delegate, then that delegate can optionally be specified with block syntax."?

I have used bare block statements on occasion and a missing ';' in the wrong place would be nasty to parse. Another option for killing that problem would be to forbid overloading only on a trailing delegate so Foo(int) and Foo(int, int delegate()) would be considered ambiguous (that argues for the ... as then the rule would be to forbid overloading only on block delegates)
Feb 04 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff24108cb552c70a0af6c news.digitalmars.com...
 Hello Nick,

 One #1 I'd be inclined to requier that the function be defined like

 void DoIt(int delegate(int) dg...)

http://www.digitalmars.com/d/1.0/function.html

think the function header should be required to indicate "this uses block syntax"? What's wrong with just saying "If the last arg a function takes is a delegate, then that delegate can optionally be specified with block syntax."?

I have used bare block statements on occasion and a missing ';' in the wrong place would be nasty to parse. Another option for killing that problem would be to forbid overloading only on a trailing delegate so Foo(int) and Foo(int, int delegate()) would be considered ambiguous (that argues for the ... as then the rule would be to forbid overloading only on block delegates)

I think I see what you mean. Although, that does create an inconsistency that bothers me a bit, because then some functions with trailing delegate params could be called with block syntax and others couldn't. And then the ones that can be called that way have a restriction on overloading and the ones that can't, don't have that restriction. Just seems messy to me. Maybe instead of requiring anything in the declaration, any use of the block statement style could be required to include a paramater list (and disallowing block statement style for varargs): void foo(int a) {/*stuff*/} void foo(int a, void dg(void)) {/*stuff*/} // Ok foo(5, { writefln("hi"); } ); // Ok, calls foo(int) foo(5); { writefln("hi"); } // Illegal (because of [1]) *even* if the // "foo(int)" overload doesn't exist foo(5) { writefln("hi"); } // Ok, calls foo(int, void delegate(void)) foo(5) (void) { writefln("hi"); } // Illegal, because of [2] foo(5); (void) { writefln("hi"); } // [1]: Already Illegal: // (However, this would become ambiguous with [3], // but that could be solved by block-statement-style // being disallowed for varargs) writefln("hi") { writefln("hi"); } // [2]: Already Illegal? (Or is it a "verb-less" // delegate literal expression statement?): (int a) { writefln("hi"); } // [3] writefln("hi", {writefln("hi");} ); This way, it's impossible to take valid code, add or remove a semicolon, and still have valid code (which I think was your main concern?).
Feb 04 2009
parent BCS <ao pathlink.com> writes:
Reply to Nick,

 This way, it's impossible to take valid code, add or remove a
 semicolon, and still have valid code (which I think was your main
 concern?).
 

I think that way can be made even stronger my making the delegate/block need a trailing ';' (it's a function call after all) where a bare block statement does not.
Feb 05 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 2:30 PM, Nick Sabalausky <a a.a> wrote:
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}

I don't like that

The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body).

I agree. Putting the args inside the { } is much more readable to me too. Even just putting the parens inside rather than outside seems an improvement. Or how about { int x; int y :: return x+y; }
 Or maybe parens instead of pipes (this is similar to K&R C, isn't it?):

 int add { (int x, int y)
    return x+y;
 }

K&R was like int add(x,y) int x; int y; { return x+y } --bb
Feb 04 2009
prev sibling next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 2:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Thu, Feb 5, 2009 at 2:30 PM, Nick Sabalausky <a a.a> wrote:
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}

I don't like that

The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body).

I agree. Putting the args inside the { } is much more readable to me too. Even just putting the parens inside rather than outside seems an improvement. Or how about { int x; int y :: return x+y; }

Oh, and last semicolon of a function should be optional :-) { int x; int y :: return x+y } --bb
Feb 04 2009
parent "Nick Sabalausky" <a a.a> writes:
"Bill Baxter" <wbaxter gmail.com> wrote in message 
news:mailman.651.1233813474.22690.digitalmars-d puremagic.com...
 On Thu, Feb 5, 2009 at 2:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Thu, Feb 5, 2009 at 2:30 PM, Nick Sabalausky <a a.a> wrote:
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}

I don't like that

The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body).

I agree. Putting the args inside the { } is much more readable to me too. Even just putting the parens inside rather than outside seems an improvement. Or how about { int x; int y :: return x+y; }


I'd be fine with that. Actually, I think I like that a little better (for a couple of reasons which I seem to be finding difficult to put into words. It's like, making a clear "split" or division in the block instead of having what looks like this thing that's just kind of floating around, and forever having those two "grouping openers" right next to each other, ie, "{ (" or "{ |" . ) But I'm not sure about replacing the commas with semicolons, unless it meant you could do: { int x, y :: return x+y; } But then, I'm not sure how I feel about that either.
 K&R was like
     int add(x,y)
        int x;
        int y;
     {  return x+y }

Oh that's right, I knew it was something funky like that. (That would be a "bad redundancy". /me nods to Walter's Dobbs article.)
 Oh, and last semicolon of a function should be optional :-)

    { int x; int y :: return x+y }

Now there's a language war waiting to happen ;)
Feb 04 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 3:20 PM, Nick Sabalausky <a a.a> wrote:
 K&R was like
     int add(x,y)
        int x;
        int y;
     {  return x+y }

Oh that's right, I knew it was something funky like that. (That would be a "bad redundancy". /me nods to Walter's Dobbs article.)

Well the nice thing about it was you could do this: int add(x,y) CrazyLongTypeName x,y; { return x+y } Thereby removing some bad redundancy. --bb
Feb 04 2009
prev sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Feb 5, 2009 at 1:20 AM, Nick Sabalausky <a a.a> wrote:
 Oh, and last semicolon of a function should be optional :-)

    { int x; int y :: return x+y }

Now there's a language war waiting to happen ;)

Psh! All that has to happen grammatically is that instead of using a raw semicolon to terminate statements, you have a StatementTerminator nonterminal which goes to either semicolon or non-consuming right brace. It's trivial to implement in the compiler too.
Feb 04 2009
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Yigal,

 Personally I prefer to have syntax for "blocks" like Ruby/smalltalk.
 given the following example function:
 int func(int a, delegate int(int) dg) { .. }
 // call func with [something in this spirit is my favorite]:
 func(someInt) { | int a, int b | return a+b; };
 

how about require that the block arg in the called function name the args
 int func(int a, delegate int(int val, int thing) dg) { .. }

and then pull in those names implicitly
 func(someInt) { return val+thing; };

This would have implication in overloading and what not but it would be syntactically clean.
Feb 05 2009
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
BCS wrote:
 Reply to Yigal,
 
 Personally I prefer to have syntax for "blocks" like Ruby/smalltalk.
 given the following example function:
 int func(int a, delegate int(int) dg) { .. }
 // call func with [something in this spirit is my favorite]:
 func(someInt) { | int a, int b | return a+b; };

how about require that the block arg in the called function name the args
 int func(int a, delegate int(int val, int thing) dg) { .. }

and then pull in those names implicitly
 func(someInt) { return val+thing; };

This would have implication in overloading and what not but it would be syntactically clean.

Ew, no. Aside from the technical issues, this distances the names from the use thereof (i.e. they'd likely be in separate files)
Feb 05 2009
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Robert Fraser wrote:
 BCS wrote:
 Reply to Yigal,

 Personally I prefer to have syntax for "blocks" like Ruby/smalltalk.
 given the following example function:
 int func(int a, delegate int(int) dg) { .. }
 // call func with [something in this spirit is my favorite]:
 func(someInt) { | int a, int b | return a+b; };

how about require that the block arg in the called function name the args
 int func(int a, delegate int(int val, int thing) dg) { .. }

and then pull in those names implicitly
 func(someInt) { return val+thing; };

This would have implication in overloading and what not but it would be syntactically clean.

Ew, no. Aside from the technical issues, this distances the names from the use thereof (i.e. they'd likely be in separate files)

While I fundamentally agree, it could also be nice to /allow/ the names in the decleration, as they may be useful for documentation. -- Chris Nicholson-Sauls
Feb 05 2009
prev sibling parent reply hsyl20 <hsyl20 yahoo.fr> writes:
 In D (with dlibs) it is:
 
 auto a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42];
 auto b = a.filter((int i){return !(i % 2);});
 
 In Python:
 
 a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42]
 b = [x for x in a if not(i % 2)]

In Scala : val a = List(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42) val b = a filter (_ % 2 == 0) or val b = a filter (e => e % 2 == 0) or val b = a filter (e : Int => e % 2 == 0) or val b = for (e <- a if (e % 2 == 0)) yield e The first notation "_ % 2 == 0" has no boilerplate and Scala is statically typed (unlike Python). Cheers, Sylvain
Feb 04 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
hsyl20:
 In Scala :
 The first notation "_ % 2 == 0" has no boilerplate and Scala is statically
typed (unlike Python).

There's a subtle line between "no boilerplate" and "magic (variables)", and the Python syntax is less magic there. So thanks but no thanks. I like the type system of Scala, but not every other thing it currently contains. And if you want static typing take a look at ShedSkin, or RPython. Bye, bearophile
Feb 04 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"hsyl20" <hsyl20 yahoo.fr> wrote in message 
news:gmd862$1741$1 digitalmars.com...
 In D (with dlibs) it is:

 auto a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42];
 auto b = a.filter((int i){return !(i % 2);});

 In Python:

 a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42]
 b = [x for x in a if not(i % 2)]

In Scala : val a = List(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42) val b = a filter (_ % 2 == 0) or val b = a filter (e => e % 2 == 0) or val b = a filter (e : Int => e % 2 == 0) or val b = for (e <- a if (e % 2 == 0)) yield e The first notation "_ % 2 == 0" has no boilerplate and Scala is statically typed (unlike Python).

I like that very much, especially since you can use either the implicit _ or a manually named var. Although I would prefer something like "a", "b", etc, (or maybe "_1", "_2",. etc) instead of "_", because "_" doesn't seem to lend itself well to multi-arg lambdas, for instance, with reduce(). I don't like *needing* to name a var when it's something trivial like in the above examples.
Feb 04 2009
parent reply hsyl20 <hsyl20 yahoo.fr> writes:
Nick Sabalausky Wrote:
 The first notation "_ % 2 == 0" has no boilerplate and Scala is statically 
 typed (unlike Python).

I like that very much, especially since you can use either the implicit _ or a manually named var. Although I would prefer something like "a", "b", etc, (or maybe "_1", "_2",. etc) instead of "_", because "_" doesn't seem to lend itself well to multi-arg lambdas, for instance, with reduce(). I don't like *needing* to name a var when it's something trivial like in the above examples.

You can use several "_", for instance: scala> val a = List(10,5,2,48,75,84,96,85,3,21,52) a: List[Int] = List(10, 5, 2, 48, 75, 84, 96, 85, 3, 21, 52) scala> val b = a reduceLeft (_ + _) b: Int = 481 The only problem is if you want to change arg order. In this case you have to use named parameters. scala> val b = a reduceLeft (_ - _) b: Int = -461 scala> val b = a reduceLeft ((a,b) => b - a) b: Int = -5 Cheers Sylvain
Feb 04 2009
parent Yigal Chripun <yigal100 gmail.com> writes:
hsyl20 wrote:
 Nick Sabalausky Wrote:
 The first notation "_ % 2 == 0" has no boilerplate and Scala is statically
 typed (unlike Python).

a manually named var. Although I would prefer something like "a", "b", etc, (or maybe "_1", "_2",. etc) instead of "_", because "_" doesn't seem to lend itself well to multi-arg lambdas, for instance, with reduce(). I don't like *needing* to name a var when it's something trivial like in the above examples.

You can use several "_", for instance: scala> val a = List(10,5,2,48,75,84,96,85,3,21,52) a: List[Int] = List(10, 5, 2, 48, 75, 84, 96, 85, 3, 21, 52) scala> val b = a reduceLeft (_ + _) b: Int = 481 The only problem is if you want to change arg order. In this case you have to use named parameters. scala> val b = a reduceLeft (_ - _) b: Int = -461 scala> val b = a reduceLeft ((a,b) => b - a) b: Int = -5 Cheers Sylvain

this seems counter-intuitive to me. Nemerle uses this syntax for currying which seems to me a much better meaning to this syntax. for example ( using D like syntax): int func (string a, char b, int c) { ... } auto a = func( "hello", _, 8); the above is syntax sugar for: auto a = int(char b) { return func("hello", b, 8); };
Feb 05 2009