C++でモナド

檜山先生のモナドの説明を純粋関数型言語C++で書いてみました。

#include "stdafx.h"

template<int n>
struct int_{static const int value=n;};


//例の最初に出てくる副作用ありバージョンはそもそも記述できないのでいきなり副作用なしバージョン。

template<typename T,typename C>
struct Countup;
template<typename T,int countup>
struct Countup<T,int_<countup>> {};



template<typename x,typename y>
struct sum_countup5_ex;
template<int x,int xc,int y,int yc>
struct sum_countup5_ex<Countup<int_<x>,int_<xc>>,Countup<int_<y>,int_<yc>>> {
  typedef Countup<int_<x+y>,int_<xc+yc+5>> result;
};


template<typename t>
struct noeffect {
  typedef Countup<t,int_<0>> result;
};

//テンプレートは文字列を扱えないのでちょっとずるをする
#define sizeof_v(v) (sizeof(v) / sizeof(v[0]))
#define sizeof_s(s) (sizeof_v(s) - 1) //\0のぶん
template<int n>
struct length_countup {
  typedef Countup<int_<n>,int_<n>> result;
};

template<typename t>
struct countup_ex;
template<int r,int c>
struct countup_ex<Countup<int_<r>,int_<c>>> {
  typedef Countup<void,int_<r+c>> result;
};


//カウントアップされる本体
int count=0;

template<typename T>
struct CountupMain;

template<int value,int countup>
struct CountupMain<Countup<int_<value>,int_<countup>>> {
  static int exec() {
    count+=countup;
    return value;
  }
};
template<int countup>
struct CountupMain<Countup<void,int_<countup>>> {
  static const char* exec() {
    count+=countup;
    return "(no result)";
  }
};

#include <iostream>
using std::cout;
using std::endl;

int _tmain(int argc, _TCHAR* argv[]) {
  cout << "count == " << count << endl;
  cout << "length_countup(\"Hello, world!\") == " 
    << CountupMain<length_countup<sizeof_s("Hello, world!")>::result>::exec() << endl;
  cout << "count == " << count << endl;
  cout << "noeffect(1) == " << CountupMain<noeffect<int_<1>>::result>::exec() << endl;
  cout << "count == " << count << endl;
  cout << "sum_countup5_ex(noeffect(1),length_countup(\"Hello, world!\")) == "
    << CountupMain<sum_countup5_ex<noeffect<int_<1>>::result,
                                   length_countup<sizeof_s("Hello, world!")>::result
                                  >::result>::exec()
    << endl;
  cout << "count == " << count << endl;
  cout << "countup_ex(sum_countup5_ex(noeffect(1),length_countup(\"Hello, world!\")) == "
    << CountupMain<countup_ex<sum_countup5_ex<
                             noeffect<int_<1>>::result,
                             length_countup<sizeof_s("Hello, world!")>::result
                          >::result>::result>::exec()
    << endl;
  cout << "count == " << count << endl;
}

副作用がみごとにCoutupMain<>::exec()の中にまとめられてしまいました。

count == 0
length_countup("Hello, world!") == 13
count == 13
noeffect(1) == 1
count == 13
sum_countup5_ex(noeffect(1),length_countup("Hello, world!")) == 14
count == 31
countup_ex(sum_countup5_ex(noeffect(1),length_countup("Hello, world!")) == (no r
esult)
count == 63