手続きの合成:問題1.41~問題1.44
手続きの合成の一般的な記述とかよくわからなくて結構ハマる。
頼みの綱は、「C++11というかboostを作った変態魔法使いたちが、
10年以上前に出て以来業界でめちゃんこ有名なSICPの、
第1章に出てる程度のことを簡単に実装できないようなライブラリを作るはずがない。
出来ないのは自分の理解がまずいのだ。」という、
最後の部分以外はあまり根拠のない思い。
それでなんとかSchemeの
((double
(double (double inc))) 5)にあたるものは作れるようになったが、
(double
double)はつまづく。
autoとかテンプレートとかfunctionラッパとかごちゃ混ぜで、
いい加減に使っていたから、なんかテンプレートの記述がえらいぐちゃぐちゃしてくる。
とりあえず何とかcomposeの実装らしきものはできたから、
あとはまたの機会にアレキサンドレスクでも見ながら考えるしかないか・・・
と思っていたら早速問題1.43のrepeatの再帰実装でつまづく。
再帰が入ると、関数の型の扱いがいい加減だと
テンプレート型がバースト的に肥大化するようなので、
いい加減にやっていたら誤魔化しが効かない。
アレキサンドレスク Modern C++ Design |
アレクサンドレスクで言うチェインを実装しないといけない。
でもまた根拠無く「アレクサンドレスクは有名なド変態魔術書だが10年以上前の本。
アレクサンドレスクのあとのboostの進化で、Lokiで出来ることはきっと組み込まれいて、
C++11に生かされているはず。自分が知らないだけ!」と思い込むことにする。
まずはfunctionラッパをメインに据えて、
1.3.1節からすべてのプログラムを書きなおす。
すこしfunctionラッパの使い方が見えてきたか。
問題1.41の(double double)は
(C++ではdoubleは使えないからdoublingという名にした)
最初にdoublingで2重化する型を具体的に解決するトリガーが必要で、
まだ完全ではない。が、よくよく考えてみれば、repeatでは繰り返し回数が変数だが、
doublingは2回とわかっているのだから、
テンプレートで解決できるはずじゃないかと思うが、
(doubling(doubling(doubling<int>)))(inc)(5)
とかやってもうまくパターンマッチしないなあ。
----
template<typename
FReturn,typename FArgument,
typename GReturn,typename GArgument>
const
function<FReturn(GArgument)>
compose(const
function<FReturn(FArgument)>& f,
const
function<GReturn(GArgument)>& g)
{
using namespace std::placeholders;
return(bind(f, bind(g, _1)));
}
template<typename
ReturnType>
const
function<ReturnType(ReturnType)>
repeated(const
function<ReturnType(ReturnType)>& f,const int n)
{
const
function<ReturnType(ReturnType)>
identity=[](const ReturnType
x){return(x);};
if(0==n){return(identity);}
else if(1==n){return(f);}
else{return(compose(f,repeated(f,n-1)));}
}
template<typename
ReturnType>
const
function<ReturnType(ReturnType)>
doubling(const
function<ReturnType(ReturnType)>& f)
{
//return(compose(f,f));
return(repeated(f,2));
}
const
int increment(const int i){return(i+1);}
template<typename
ResultType>
const
ResultType squareFun(const ResultType x){return(x*x);}
const
function<double(double)>
smoothNTime(const
function<double(double)>& f,
const double smoothLength, const int n)
{
function<function<double(double)>(function<double(double)>)>
smooth1Time;
smooth1Time=[smoothLength](const
function<double(double)>& f){
return([f,smoothLength](const double x)
{return((f(x-smoothLength)+f(x)+f(x+smoothLength))/3.0);});
};
return(repeated(smooth1Time,n)(f));
}
const
function<double(double)>
smooth(const
function<double(double)>& f,
const double smoothLength)
{
return(smoothNTime(f,smoothLength,1));
}
int
main(int argc, char** argv)
{
const function<int(int)>
inc=increment;
const
function<function<int(int)>(function<int(int)>)>
doublingInt=doubling<int>;
cout<<"Excersize
1.41:"<<endl;
cout<<"((double inc)
5)="<<(doubling(inc))(5)<<endl;
cout<<"(((double (double
double)) inc) 5)="
<<(doubling(doubling(doublingInt)))(inc)(5)<<endl;
//cout<<(doubling(doubling(doubling<int>)))(inc)(5)<<endl;
cout<<endl<<"Excersize
1.42:"<<endl;
const function<int(int)>
square=squareFun<int>;
cout<<"((compose square inc)
6)="
<<compose(square,inc)(6)<<endl;
cout<<endl<<"Excersize
1.43:"<<endl;
const function<double(double)>
dsquare=squareFun<double>;
cout<<"((repeated square 2)
5)="
<<repeated(dsquare,2)(5.0)<<endl;
cout<<endl<<"Excersize
1.44: data is put out to files."<<endl;
ofstream outFile("out.txt");
ofstream outFile1("out1.txt");
ofstream outFile5("out5.txt");
const double dx=2.0;
const double smoothLength(1.0);
const function<double(double)> f=
[](const double y){return(sin(y));};
for(int ix=0;ix<100;++ix){
const double x(dx*ix);
outFile<<x<<"
"<<f(x)<<endl;
outFile1<<x<<"
"<<smooth(f,smoothLength)(x)<<endl;
outFile5<<x<<"
"<<smoothNTime(f,smoothLength,5)(x)<<endl;
}
outFile.close();
outFile1.close();
outFile5.close();
return(0);
}
----
出力
----
Excersize
1.41:
((double
inc) 5)=7
(((double
(double double)) inc) 5)=21
Excersize
1.42:
((compose
square inc) 6)=49
Excersize
1.43:
((repeated
square 2) 5)=625
Excersize
1.44: data is put out to files.
0 件のコメント :
コメントを投稿