digitalmars.D.learn - std.algorithm.map with multiple lambdas (2.066.0-b1) (does not
- klasbo (38/38) Jul 05 2014 void main(){
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (14/14) Jul 05 2014 This is an instance of these bugs:
- klasbo (40/48) Jul 05 2014 This problem was introduced when std.algorithm.map was made to
void main(){ import std.algorithm, std.stdio; auto arr = [1,2,3]; arr.map!("a + a", "a * a").writeln; //compiles arr.map!(a => a + a, a => a * a).writeln; //does not } If I define two functions outside main, it works: void main(){ import std.algorithm, std.stdio; auto arr = [1,2,3]; arr.map!(twoTimes, square).writeln; } int square(int i){ return i*i; } int twoTimes(int i){ return i+i; } However, if `twoTimes` and `square` are nested inside of main(), it fails. [...]\typetuple.d(550): Error: template instance F!(twoTimes) cannot use local 'twoTimes' as parameter to non-global template AppliedReturnType(alias f) [...]\typetuple.d(556): Error: template instance maptest.main.staticMap!(AppliedReturnType, twoTimes) error instantiating [...]\algorithm.d(415): instantiated from here: staticMap!(AppliedReturnType, twoTimes, square) .\maptest.d(8): instantiated from here: map!(int[]) The alias declaration `alias AppliedReturnType(alias f) = typeof(f(r.front));` ... is something I have never seen before. So I hardcoded/expanded this line: `alias ReturnTypes = TypeTuple!(AppliedReturnType!(_funs[0]), AppliedReturnType!(_funs[1]));` ... which gives me the same error (cannot use local as parameter to non-global). So I threw it in a pragma(msg, [...]): `pragma(msg, TypeTuple!(AppliedReturnType!(_funs[0]), AppliedReturnType!(_funs[1])));` ... which printed `(int, int)`, as expected. And also the same error. Wat.
Jul 05 2014
This is an instance of these bugs: https://issues.dlang.org/show_bug.cgi?id=5710 https://issues.dlang.org/show_bug.cgi?id=11946 But seeing that `map` works with a single lambda/local function, it should be possible to make it work with several ones too. For the time being, a simple workaround is to make the local functions static: void main() { static int square(int i) { return i*i; } static int twoTimes(int i) { return i+i; } import std.algorithm, std.stdio; auto arr = [1,2,3]; arr.map!(twoTimes, square).writeln; }
Jul 05 2014
On Saturday, 5 July 2014 at 19:31:24 UTC, Marc Schütz wrote:This is an instance of these bugs: https://issues.dlang.org/show_bug.cgi?id=5710 https://issues.dlang.org/show_bug.cgi?id=11946 But seeing that `map` works with a single lambda/local function, it should be possible to make it work with several ones too. For the time being, a simple workaround is to make the local functions static:This problem was introduced when std.algorithm.map was made to refuse void functions. But map already did fail void when it gets multiple functions, because std.typecons.tuple refuses variables of type void (though the error message is cryptic, sure): "Error: variable std.typecons.Tuple!void.Tuple._expand_field_0 variables cannot be of type void" The only thing map didn't fail was single argument void. This was fixed, so why not re-use the same fix for multiple arguments? The example below works fine, and gives the new and sensible-er error message: template map(fun...) if (fun.length >= 1) { auto map(Range)(Range r) if (isInputRange!(Unqual!Range)) { alias AppliedReturnType(alias f) = typeof(f(r.front)); static if (fun.length > 1) { import std.functional : adjoin; import std.typetuple : staticIndexOf; alias _funs = staticMap!(unaryFun, fun); alias _fun = adjoin!_funs; // Attack of the copy-paste and poorly chosen variable name: foreach(_f; _funs){ static assert(!is(AppliedReturnType!_f == void), "All mapping functions must not return void."); } } else { alias _fun = unaryFun!fun; static assert(!is(AppliedReturnType!_fun == void), "Mapping function must not return void."); } return MapResult!(_fun, Range)(r); } } Am I missing something?
Jul 05 2014