templates - D 中柯里化(Currying)函数的模板?

标签 templates d

是否可以编写一个模板或类似的模板来自动柯里化(Currying) D 中的函数?手动写出所有嵌套的委托(delegate)简直要了我的命。

基本上,对于函数 f ,例如3 个参数,通常可以像 f(a,b,c) 那样调用,我希望它可以像 f(a)(b)(c) 那样调用。

我知道std.functional.partial ,但这不是我想要的。我想翻译函数定义端,而不是调用端。

我也知道这远非最佳实践,但我正在生成代码,所以请耐心等待。

最佳答案

嗯,按照这些思路应该可以完成工作:

template autocurry(alias what) {
        import std.traits;
        static if(Parameters!what.length)
                auto autocurry(Parameters!what[0] arg) {
                        alias Remainder = Parameters!what[1 .. $];
                        auto dg = delegate(Remainder args) {
                                return what(arg, args);
                        };

                        static if(Remainder.length > 1)
                                return &autocurry!dg;
                        else
                                return dg;
                }
        else
                alias autocurry = what;
}

int foo(int a, string b, float c) {
        import std.stdio; writeln(a, " ", b, " ", c);
        return 42;
}

string test() {
        import std.stdio; writeln("called test");
        return "no args";
}

void main() {
        import std.stdio;
        alias lol = autocurry!foo;
        writeln(lol(30)("lol")(5.3));

        auto partial = lol(20);
        partial("wtf")(10.5);

        alias t = autocurry!test;
        writeln(t());
}

这个想法非常简单:根据剩余参数生成辅助函数 - 如果有的话,返回辅助函数的地址作为委托(delegate),否则,只返回调用收集到的参数的委托(delegate)。一点递归性可以处理 1+ arg 的情况,而外部的静态 if 通过仅返回原始函数来处理 0 arg 的情况。

需要注意的语言特征:

  • 同名模板。当模板具有与模板同名的成员(在本例中为 autocurry)时,使用时会自动引用它。

  • 元组扩展。当我调用what(arg, args)时,args一是一个内置元组,会自动扩展以创建完整的参数列表。

  • 这里的各种自动返回(显式 auto autocurry 和隐式 delegate 关键字,不指定返回类型)只是转发主体碰巧返回的任何其他随机类型。

  • 在主函数中,我做了alias lol = autocurry!foo; (我经常使用哈哈作为占位符名称,哈哈)。您还可以在顶层重载它:

      int foo(int a, string b, float c) {
              import std.stdio; writeln(a, " ", b, " ", c);
              return 42;
      }

      alias foo = autocurry!foo; // overloads the auto-curried foo with the original foo

现在您可以直接使用它,与原始版本一起使用:

void main() {
        foo(30)("lol")(5.3); // overload resolves to curried version
        foo(40, "cool", 103.4); // overload resolves to original automatically
}

如果您更喜欢新名称或重载由您决定,则两者都可以。

请注意,每个参数都有责任分配一些内存来为下一个委托(delegate)存储它。 GC 将负责清理它。

关于templates - D 中柯里化(Currying)函数的模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58147381/

相关文章:

c++ - 专门化嵌套模板

c++ - 如何在模板类定义中构造自定义类型

d - 如何在 Windows 下反汇编 .obj 文件?

templates - 我应该在服务器端还是客户端呈现 html?

c++ - MSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的友元

c++ - 为什么 C+ +'s ` 变量模板的行为不符合预期?

d - 配置 DUB 的默认构建选项,而不影响其他构建类型

escaping - D 中的 '\?' 转义序列是什么?

traits - D 中的 'is' 语句是什么?

arrays - 在 D 函数中接收 ... 的数组数组?