あらすじ:関数ポインタを使えばしくぴーの問題は全部Cで書けるんだ!などと思っていたら compose でつまづいて関数ポインタでキーってなったので C++ に逃げてテンプレートを使ったらそれなりに動くものができたもののなにやら中途半端でイラッときたので boost を使ってみた。いまは反省している。

参考資料

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式の中で使える関数

ってことか? しかしなんだ、毎回型を書かないといけないってのがアレだな。

*1:compose square inc) 3) ; => (3+1)*(3+1) = 16 )((repeated (lambda (x) (* x 2

*2:_1*_1), (_1+1

*3:_1+1)(3