www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - delegate from lambda expression

reply "timotheecour" <thelastmammoth gmail.com> writes:
I'd like to achieve the following:
----
import std.stdio,std.range,std.algorithm,std.array;
void main(){
    auto dg=a=>a*2;
    auto a=iota(0,10);
    writeln(a.map!dg.array);
}
----
but this doesn't compile:
Error: variable [...]dg type void is inferred from initializer 
delegate (__T26 a)
{
return a * 2;
}
, and variables cannot be of type void

However this works:
    writeln(a.map!(a=>a*2).array);
but I want to reuse dg in other expressions (and avoid repeating 
myself)
Also, I want to avoid using string litteral enum dg=`a*2` as in 
my case dg is much more complicated and this is cleaner without a 
string IMHO.

My questions:
1) why can't the compiler infer the type int(int) for dg?
2) how to convert a lambda a=>a*2 to a delegate or function?
3) if 2 is not possible, how to achieve what I'm trying to do 
WITHOUT having to make the type explicit as in "int delegate(int) 
dg=(int a){return a*2;}"?
4) is there a way to have template delegates, and what's the 
syntax in this simple example?
Sep 09 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
timotheecour:

 I'd like to achieve the following:
 ----
 import std.stdio,std.range,std.algorithm,std.array;
 void main(){
    auto dg=a=>a*2;
    auto a=iota(0,10);
    writeln(a.map!dg.array);
 }
 ----
 but this doesn't compile:
 Error: variable [...]dg type void is inferred from initializer 
 delegate (__T26 a)
 {
 return a * 2;
 }
 , and variables cannot be of type void

 However this works:
    writeln(a.map!(a=>a*2).array);

Your code doesn't look good, I suggest to write less golfed D code. One solution to your problem is to define a function template (note the static, that is currently needed, but maybe not in future): import std.stdio, std.range, std.algorithm, std.array; void main() { static dg(T)(T a) { return a * 2; } auto items = iota(10); items.map!dg().array().writeln(); }
 1) why can't the compiler infer the type int(int) for dg?

Because in D there is no global inferencer, like a Hindley–Milner (and you can't defer typing as in one recent language). I think not even Scala allows you to write code similar to: auto dg = a => a * 2; You need a language with global inferencing, like Haskell, ShedSkin, Idris, etc. Bye, bearophile
Sep 09 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/10/2012 01:55 AM, bearophile wrote:
 Your code doesn't look good,

Yes it does.
Sep 09 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
 Because in D there is no global inferencer,

On the other hand it's not impossible to invent a syntax for templated lambdas, etc :-) Bye, bearophile
Sep 09 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/10/2012 01:20 AM, timotheecour wrote:
 I'd like to achieve the following:
 ----
 import std.stdio,std.range,std.algorithm,std.array;
 void main(){
     auto dg=a=>a*2;
     auto a=iota(0,10);
     writeln(a.map!dg.array);
 }
 ----
 but this doesn't compile:
 Error: variable [...]dg type void is inferred from initializer delegate
 (__T26 a)
 {
 return a * 2;
 }
 , and variables cannot be of type void

 However this works:
     writeln(a.map!(a=>a*2).array);
 but I want to reuse dg in other expressions (and avoid repeating myself)
 Also, I want to avoid using string litteral enum dg=`a*2` as in my case
 dg is much more complicated and this is cleaner without a string IMHO.

 My questions:
 1) why can't the compiler infer the type int(int) for dg?

Because it can't. D unfortunately does not have powerful type inference.
 2) how to convert a lambda a=>a*2 to a delegate or function?

Those need full type information. The lambda as shown is generic.
 3) if 2 is not possible, how to achieve what I'm trying to do WITHOUT
 having to make the type explicit as in "int delegate(int) dg=(int
 a){return a*2;}"?

template ID(alias a){ alias a ID; } void main(){ alias ID!(a=>a*2) dg; auto a=iota(0,10); writeln(a.map!dg.array); }
 4) is there a way to have template delegates, and what's the syntax in
 this simple example?

Already shown.
Sep 09 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/10/2012 02:56 AM, bearophile wrote:
 timotheecour:

 What was wrong with it and what would you suggest to improve it?

Nothing serious, I just suggest to give a bit more air to your code, adding a space around operators, after commas, etc. Otherwise your code risk looking like Timon's code ;-)

Which is usually extremely beautiful. This is not a liability.
 I have also compiled the code with -property. Some people don't like
 this. The choice is yours, but you need to express an informed choice.


 Will the way I'm skipping "()" ever be deprecated?

Who knows. People disagree on this :-)

(That means it is here to stay.)
 One of the points of UFCS was to avoid writing too much parentheses

Where did you read this?

He most definitely has a point there.
Sep 09 2012
prev sibling next sibling parent "timotheecour" <thelastmammoth gmail.com> writes:
Thanks! the template alias ID solves my problem.


 Your code doesn't look good,


What was wrong with it and what would you suggest to improve it? Also, I noticed you replaced (among other things): a.map!dg.array by a.map!dg().array() Will the way I'm skipping "()" ever be deprecated? One of the points of UFCS was to avoid writing too much parentheses (in addition to avoiding writing nested parentheses).
Sep 09 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
timotheecour:

 What was wrong with it and what would you suggest to improve it?

Nothing serious, I just suggest to give a bit more air to your code, adding a space around operators, after commas, etc. Otherwise your code risk looking like Timon's code ;-) I have also compiled the code with -property. Some people don't like this. The choice is yours, but you need to express an informed choice.
 Will the way I'm skipping "()" ever be deprecated?

Who knows. People disagree on this :-)
 One of the points of UFCS was to avoid writing too much 
 parentheses

Where did you read this? Bye, bearophile
Sep 09 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-09-10 01:20, timotheecour wrote:
 I'd like to achieve the following:
 ----
 import std.stdio,std.range,std.algorithm,std.array;
 void main(){
     auto dg=a=>a*2;
     auto a=iota(0,10);
     writeln(a.map!dg.array);
 }
 ----
 but this doesn't compile:
 Error: variable [...]dg type void is inferred from initializer delegate
 (__T26 a)
 {
 return a * 2;
 }
 , and variables cannot be of type void

 However this works:
     writeln(a.map!(a=>a*2).array);
 but I want to reuse dg in other expressions (and avoid repeating myself)
 Also, I want to avoid using string litteral enum dg=`a*2` as in my case
 dg is much more complicated and this is cleaner without a string IMHO.

 My questions:
 1) why can't the compiler infer the type int(int) for dg?
 2) how to convert a lambda a=>a*2 to a delegate or function?

Try this: auto dg = (int a) => a * 2; If that doesn't work, this should: auto dg = (int a) { return a * 2; }; -- /Jacob Carlborg
Sep 10 2012