我正在尝试实现经典的高阶范围zipWith
,如下所示
import std.traits: allSatisfy;
import std.range: isInputRange;
auto zipWith(fun, Ranges...)(Ranges ranges) if (Ranges.length >= 2 && allSatisfy!(isInputRange, Ranges))
{
import std.range: zip;
return zip(ranges).map!fun;
}
但是
unittest
{
auto x = [1, 2, 3, 4, 5];
zipWith!((a, b) => a + b)(x, x);
}
失败并显示错误
template algorithm_ex.zipWith cannot deduce function from argument types !((a, b) => a + b)(int[], int[]), candidates are: (d-dmd-unittest)
algorithm_ex.zipWith(fun, Ranges...)(Ranges ranges) if (Ranges.length && allSatisfy!(isInputRange, Ranges))
我不明白为什么。有线索吗?
更新:
在CyberShadows回答之后,我现在有了
import std.traits: allSatisfy;
/** Zip $(D ranges) together with operation $(D fun).
TODO: Simplify when Issue 8715 is fixed providing zipWith
*/
auto zipWith(alias fun, Ranges...)(Ranges ranges) if (Ranges.length >= 2 && allSatisfy!(isInputRange, Ranges)) {
import std.range: zip;
import std.algorithm: map;
import std.functional: binaryFun;
static if (ranges.length == 2)
return zip(ranges).map!(a => binaryFun!fun(a.expand));
else if (ranges.length >= 3)
return zip(ranges).map!(a => naryFun(a.expand));
else
static assert(false, "Need at least 2 range arguments.");
}
unittest {
auto x = [1, 2, 3];
import std.array: array;
assert(zipWith!"a+b"(x, x).array == [2, 4, 6]);
assert(zipWith!((a, b) => a + b)(x, x).array == [2, 4, 6]);
assert(zipWith!"a+b+c"(x, x, x).array == [3, 6, 9]);
}
是否可以通过字符串扩展它来支持nary fun,例如zipWith!"a+b+c"(x,x,x)
?我特别要求,因为我注意到std.functional中存在naryFun
的代码,但它被注释掉了。
答案 0 :(得分:5)
您必须将fun
模板参数声明为alias
参数,否则将其声明为类型参数:
auto zipWith(alias fun, Ranges...)( // ...
您需要为std.algorithm
导入map
。
std.range.zip
将返回std.typecons.Tuple
的范围,该范围不会自动扩展为lambda的两个参数。您需要明确地扩展元组。
固定代码:
import std.traits: allSatisfy;
import std.range: isInputRange;
import std.algorithm: map;
auto zipWith(alias fun, Ranges...)(Ranges ranges) if (Ranges.length >= 2 && allSatisfy!(isInputRange, Ranges))
{
import std.range: zip;
return zip(ranges).map!(t => fun(t.expand));
}
unittest
{
auto x = [1, 2, 3, 4, 5];
zipWith!((a, b) => a + b)(x, x);
}
是否可以通过字符串扩展它以支持nary fun's,例如
zipWith!"a+b+c"(x,x,x)
?
我不明白为什么不:
import std.string;
private string genNaryFun(string fun, V...)()
{
string code;
foreach (n, v; V)
code ~= "alias values[%d] %s;".format(n, cast(char)('a'+n));
code ~= "return " ~ fun ~ ";";
return code;
}
template naryFun(string fun)
{
auto naryFun(V...)(V values)
{
mixin(genNaryFun!(fun, V));
}
}
unittest
{
alias naryFun!"a + b + c" test;
assert(test(1, 2, 3) == 6);
}