Nor*_*löw 4 d range higher-order-functions
我正在尝试实现经典的高阶范围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;
}
Run Code Online (Sandbox Code Playgroud)
但是
unittest
{
auto x = [1, 2, 3, 4, 5];
zipWith!((a, b) => a + b)(x, x);
}
Run Code Online (Sandbox Code Playgroud)
失败,错误
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))
Run Code Online (Sandbox Code Playgroud)
而且我不明白为什么.有线索吗?
更新:
在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]);
}
Run Code Online (Sandbox Code Playgroud)
是否有可能通过字符串扩展它以支持nary fun's zipWith!"a+b+c"(x,x,x)?我特别要求,因为我注意到naryFunstd.functional 中有代码,但它被注释掉了.
您必须将fun模板参数声明为alias参数,否则将其声明为类型参数:
auto zipWith(alias fun, Ranges...)( // ...
Run Code Online (Sandbox Code Playgroud)您需要导入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);
}
Run Code Online (Sandbox Code Playgroud)
是否有可能通过字符串扩展它以支持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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
121 次 |
| 最近记录: |