■
あらすじ:関数ポインタを使えばしくぴーの問題は全部Cで書けるんだ!などと思っていたら compose でつまづいて関数ポインタでキーってなったので C++ に逃げてテンプレートを使ったらそれなりに動くものができたもののなにやら中途半端でイラッときたので boost を使ってみた。いまは反省している。
参考資料
- http://www.kmonos.net/alang/boost/classes/function.html
- http://www.kmonos.net/alang/boost/classes/lambda.html
- http://www.kmonos.net/pub/BoostBook/BoostCppP2Chap6.pdf
compose というのは引数として受けとった複数個の関数を合成した関数を返す関数で、Scheme だと lambda を使って簡単に書ける。で、compose が書けると引数として受け取った関数を n 回繰り返す関数を返す関数であるところの repeated も書ける。
(define (compose f g) (lambda (x) (f (g x)))) (define (repeated f n) (if (= n 1) f (compose f (repeated f (- n 1)))))
こんなんが書けると
(define (inc x) (+x 1)) (define (square x) (* x x)) *1( 10) 1) ; => 1*2^10 = 1024
とかができる。同じことを boost::lambda を使って書くとこうなる。boost::function も使う。
#import#import #import using namespace boost; using namespace boost::lambda; template function compose(function f, function g){ return function (bind(f, bind(g, _1))); } template function repeated(function f, int n){ if(n == 1) return function (bind(f, _1)); else return compose(f, repeated(f, n-1)); }
詳しくは参考資料を見ていただくとして、まあとりあえずこんなんが書けて
int inc(int a){ return a+1;} int square(int a){ return a*a;} int x2(int a){ return a*2;}
とか定義してあると
std::cout << compose(square, inc)(3) << std::endl; // => (3+1)*(3+1) = 16 std::cout << repeated (x2, 10)(1) << std::endl; // => 1*2^10 = 1024
とか書ける。inc とか square などのショボい関数ならその場で書いてもいいんじゃないでしょうか。
std::cout << compose)*2((3) << std::endl; // => (3+1)*(3+1) = 16 std::cout << repeated ((_1*2), 10)(1) << std::endl; // => 1*2^10 = 1024
つうか上なら compose なしで
((lambda (x) (* x x)) ((lambda (x) (+ x 1)) 3))
こんな感じで書けるんちゃいますのん? というわけでこうなる。
std::cout << function(_1*_1)(function (_1+1)(3)) << std::endl; // => 1*2^10 = 1024
ちなみに
// std::cout << (_1*_1))*3( << std::endl;
だとエラーが大量に出て驚く。要するに
- boost::function
(lambda式) -> 普通に使える関数 - boost::lambda::bind(普通の関数) ->lambda式の中で使える関数
ってことか? しかしなんだ、毎回型を書かないといけないってのがアレだな。