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でも扱えたよね。
- これはD言語自体の弱点でもあります。
- boost::functionのような物はない
- autoあるから別にいいよね!
バグとかあっても気にしないで下さい。嘘です気づいたら教えてもらえるとありがたいです。まあネタなので誰も気にしない気がします。