FunctionalFunction

勢い余って変な物を作ってしまいました。
(良く知りませんが)関数型言語では、関数の引数が足りなかった場合、勝手にカリー化してくれます。
それの何がいいの?は兎も角として、Dにもそういう関数があってもいいんじゃないかと思いました。
ということで「関数型チックなファンクタ」です。勝手にFunctionalFunctionとか命名しましたが英語はよく分かりません。
以下クラス定義。

class Functional(alias func, int n = 0){
static:
    alias ReturnType!(func) Ret;
    alias ParameterTypeTuple!(func)[0..n] preArgs;
    alias ParameterTypeTuple!(func)[n..$] Args;

    ReturnType!(f!(T)) opCall(T...)(T t){
        return f!(T)(t);
    }

    template f(T...){
        static assert(ArgsCheck!(Args.length, Args, T), "bad parameter error");
        static if (is(T == Args)){
            Ret f(Args args){
                return func(args_, args);
            }
        } else {
            Functional!(func, T.length) f(T t){
                return new Functional!(func, T.length)(t);
            }
        }
    }

    this(preArgs args){
        foreach(i,x; args){
            args_[i] = x;
        }
    }

private:
    preArgs args_;

    template ArgsCheck(int n, T...){
        static if (is(T[0..n] == T[n..$])){
            const ArgsCheck = true;
        } else static if (n == 0){
            const ArgsCheck = false;
        } else {
            const ArgsCheck = ArgsCheck!(n-1, T[0..n-1], T[n..$]);
        }
    }
}

以下使用例。

int f(int x, int y){ // 普通の関数宣言
    return x + y;
}
Functional!(f) func; // 新スタイルの関数宣言!

void main(){
    writefln(func(3,4));  // 7
    auto x = func(4);
    writefln(x(2));       // 6
    writefln(func(1)(6)); // 5
}

「新スタイルの関数宣言」はid:shinichiro_hさんの命名です。新スタイルです。クール。
さて早速ですが、このファンクタの弱点をいくつか…いきなり弱点とかよわよわですね。

  • 関数の引数の型は、テンプレート引数の値パラメタと同じ「整数型、 浮動小数点型、文字列型のみ」に制限される。
  • 関数の引数の値は、テンプレート引数の値パラメタと同じ「コンパイル時定数のみ」に制限される。
    • カリー化する際に、関数の引数の値を式タプルとして保持するためです。
  • 元になる関数がオーバーロードされているとうまくいかない。
    • std.traitsによる型の取得がうまくいかないためです。
  • メンバ関数を扱えない。
    • これはD言語自体の弱点でもあります。
      • 適当言わないで下さい。Dでも扱えたよね。
  • boost::functionのような物はない
    • autoあるから別にいいよね!

バグとかあっても気にしないで下さい。嘘です気づいたら教えてもらえるとありがたいです。まあネタなので誰も気にしない気がします。