複素数とパッケージ
ここで言うパっケージを表現するのは、C++ではまあクラスだわな。
抽象クラスでインターフェースを定義して、
継承で具体的に実装する話と思っていいのだろう。
オブジェクト指向はあくまで、数あるデータ/手続き構造の表現の中の一つに過ぎない、
というのも今までこの本で学んだことだが、ここではオブジェクト指向が向いていそう。
クラスでなくnamespaceでもいいような気がするが、まずは慣れ親しんだクラスで。
getやputの部分はかなり問題。
本格的には3.3.3節でしっかり実装されるわけだが、
C++の関数の型の扱いが重くのしかかる。
関数をこういう扱いするときは、lispの表現力の高さが感じられるなあ。
「警戒すべきライバルとそうでないところとを見分けられるようになった。
...
C++プログラマを募集しているところも安全だ。」
とか言われると、自分はC++をこちょこちょいじくって何をやっているんだろうと不安になる。
実際作っていて、殆どの作業は型インターフェースの調整に費やされているわけで、
「Schemeではこんなの考えなくていいのに・・・
型があるから、何をしているかSchemeより分かりやすいというのはあるのだが、
本当に考えるべきなのは、型の調整なんかじゃないんじゃないんだろうか」
という思いがふつふつと湧く。
putとgetは3.3.3節で、メッセージパッシングを使った、
意外な形の実装がしっかりとなされるが、
ここでは面倒なので敢えてそこまでしないで、
3.3.3節との比較のために、もっと単純なテーブル管理クラスを作って、
グローバルスコープに置いておく。
またListの内部実装に、関数を格納するクラスを継承で実装。
実行できる形でリスト内から関数を取り出すため、
executable関数を作ったが、そのテンプレートパラメターがウザい。
今のところ関数の型自体は動的生成というわけでないので、
コンパイル時に解決できるはずだし、実行時にRTTIで試してみても、
関数の型情報はちゃんと伝わっている。
だから少なくともテンプレートパラメタについては、なくても済ませられるはずだが、
まずは動くものを作っておこう。
apply-generic内のSchemeのapplyを表現するには、
C++では任意個のplaceholderに対して、
bindで再帰的な部分適用をすることが必要だが、
これはC++11を持ってしても難しい・・・。
よく見ればapply自体の表現はapply-genericで必須ではないのだが、
どの道個々のargsからタグをcontentsで引っ剥がした引数リストを、
getの結果帰ってくる関数に渡さにゃいかんわけで、
任意個の場合にこれはどうすればいいものやら・・・lispの表現力すごいなあ。
さしあたっては、実際のargsは、
複素数(や有理数・有理関数)の引数が1個か2個の時が多分殆どだろうから、
argsが1個の時と2個の時を別々に書いてオーバーロードすることにする。
いずれ任意個のが必要になる時が来るのかなあ・・・。
メンバ関数をfunctionラッパに渡すには、
一度クロージャでキャプらないといけないらしい。
クロージャはまだ慣れないだけに安全性が心配になる。
しかしクロージャでキャプったメンバ関数の、元のクラスを試しにdeleteしてみると、
make-from-real-imagは死んだが、
deleteされたあとでもreal-partは動いている。
謎の振る舞いだが、多分コンパイラの最適化が絡んできていそうだなぁ。
----
template<typename
ReturnType, typename ...ArgTypes>
const
List makeLeaf(const function<ReturnType(ArgTypes...)>& proc){
return(make_shared<FunctionLeaf<ReturnType,ArgTypes...>>(proc));
}
template<typename
ReturnType,typename...ArgTypes>
class
FunctionLeaf:public ListTree{
public:
FunctionLeaf(void)=delete;
FunctionLeaf(const
function<ReturnType(ArgTypes...)>& procedureIn)
:ListTree(nullptr),procedure(procedureIn){}
const ReturnType operator()(const
ArgTypes... args)const{
return(this->procedure(args...));
}
virtual const bool
isFunction(void)const{return(true);}
private:
const
function<ReturnType(ArgTypes...)> procedure;
};
template
<typename ReturnType,typename ... ArgTypes>
const
function<ReturnType(ArgTypes...)>
executable(const
List& leafFunction)
{
return(*dynamic_pointer_cast<FunctionLeaf<ReturnType,ArgTypes...>>
(leafFunction));
}
//---------abstraction
barrier---------
map<string,List>
table;
void
put(const string operation, const string type,
const List& functionItem)
{
table.insert(make_pair(operation+type,functionItem));
}
const
List get(const string operation,const string type)
{
auto position=table.find(operation+type);
if(position==table.end()){
return(makeList());
}
return(position->second);
}
//---------abstraction
barrier---------
typedef
string TagType;
const
List attachTag(const TagType typeTag,const List& contents)
{return(cons(makeLeaf(typeTag),contents));}
const
TagType typeTag(const List& datum)
{
if(isPair(datum)){return(value<TagType>(car(datum)));}
cerr<<"Bad tagged datum --
TYPE-TAG"<<listString(datum)<<endl;
exit(1);
return("");
}
const
List contents(const List& datum)
{
if(isPair(datum)){return(cdr(datum));}
cerr<<"Bad tagged datum --
CONTENTS"<<listString(datum)<<endl;
exit(1);
return(makeList());
}
const
List applyGeneric
(const
string operation, const List& arg1)
{
const TagType typeTag1(typeTag(arg1));
const List
procedureLeaf(get(operation,typeTag1));
if(isFunction(procedureLeaf)){
const auto
procedure(executable<List,List>(procedureLeaf));
return(procedure(contents(arg1)));
}
cerr<<"No method for these types
--- APPLY-Generic"
<<listString(makeList(operation,arg1))<<endl;
return(makeList());
}
const
List applyGeneric
(const
string operation, const List& arg1, const List& arg2)
{
const TagType typeTag1(typeTag(arg1));
const List
procedureLeaf(get(operation,typeTag1));
if(isFunction(procedureLeaf)){
const auto procedure(executable<List,List,List>(procedureLeaf));
return(procedure(contents(arg1),contents(arg2)));
}
cerr<<"No method for these types
--- APPLY-Generic"
<<listString(makeList(operation,arg1,arg2))<<endl;
return(makeList());
}
//---------abstraction
barrier---------
typedef
List Complex;
const
bool isRectangular(const Complex z)
{return(isEq(typeTag(z),makeLeaf("rectangular")));}
const
bool isPolar(const Complex z)
{return(isEq(typeTag(z),makeLeaf("polar")));}
class
ComplexProcedure{
public:
ComplexProcedure(void)=delete;
ComplexProcedure(const TagType
tagIn):tagString(tagIn){}
virtual ~ComplexProcedure(void){};
virtual const Complex realPart(const
Complex&)const=0;
virtual const Complex imagPart(const
Complex&)const=0;
virtual const Complex makeFromRealImag
(const Complex&, const
Complex&)const=0;
virtual const Complex magnitude(const
Complex&)const=0;
virtual const Complex angle(const
Complex&)const=0;
virtual
const Complex makeFromMagAng
(const Complex&, const
Complex&)const=0;
const TagType
getTag(void)const{return(this->tagString);}
virtual const Complex tag(const
Complex& z)const
{return(attachTag(this->getTag(),z));}
private:
const TagType tagString;
};
template
<typename FieldType>
class
ComplexRectangular :public ComplexProcedure{
public:
ComplexRectangular(void):ComplexProcedure("rectangular"){}
const Complex realPart(const Complex&
z)const override
{return(car(z));}
const Complex imagPart(const Complex&
z)const override
{return(cadr(z));}
const Complex makeFromRealImag
(const Complex& x, const Complex&
y)const override
{return(makeList(x,y));}
const Complex magnitude(const Complex&
z)const override
{
return(makeLeaf
(squareRoot
(value<FieldType>
(square(this->realPart(z))
+square(this->imagPart(z))))));
}
const Complex angle(const Complex&
z)const override
{
return(makeLeaf
(arcTangent2(value<FieldType>(this->imagPart(z)),
value<FieldType>(this->realPart(z)))));
}
const Complex makeFromMagAng
(const Complex& r, const Complex&
a)const override
{
return(this->makeFromRealImag
(makeLeaf(value<FieldType>(makeLeaf(r))*
cosine(value<FieldType>(makeLeaf(a)))),
makeLeaf(value<FieldType>(makeLeaf(r))*
sine(value<FieldType>(makeLeaf(a))))));
}
};
template
<typename FieldType>
class
ComplexPolar:public ComplexProcedure{
public:
ComplexPolar(void):ComplexProcedure("polar"){}
const Complex realPart(const Complex&
z)const override{
return(makeLeaf(value<FieldType>(this->magnitude(z))*
cosine(value<FieldType>(this->angle(z)))));
}
const Complex imagPart(const Complex&
z)const override{
return(makeLeaf(value<FieldType>(this->magnitude(z))*
sine(value<FieldType>(this->angle(z)))));
}
const Complex makeFromRealImag
(const Complex& x, const Complex&
y)const override
{
return(this->makeFromMagAng
(makeLeaf
(squareRoot(value<FieldType>(square(x)+square(y)))),
makeLeaf(arcTangent2(value<FieldType>(y),
value<FieldType>(x)))));
}
const Complex magnitude(const Complex&
z)const override
{return(car(z));}
const Complex angle(const Complex&
z)const
{return(cadr(z));}
const Complex makeFromMagAng
(const Complex& r, const Complex&
a)const override
{return(makeList(r,a));}
};
void
activateComplexPackage(ComplexProcedure* _complex)
{
put("real-part",_complex->getTag(),
makeLeaf(function<Complex(Complex)>
([_complex](const Complex& z)
{return(_complex->realPart(z));})));
put("imag-part",_complex->getTag(),
makeLeaf(function<Complex(Complex)>
([_complex](const Complex& z)
{return(_complex->imagPart(z));})));
put("magnitude",_complex->getTag(),
makeLeaf(function<Complex(Complex)>
([_complex](const Complex& z)
{return(_complex->magnitude(z));})));
put("angle",_complex->getTag(),
makeLeaf(function<Complex(Complex)>
([_complex](const Complex& z)
{return(_complex->angle(z));})));
put("make-from-real-imag",_complex->getTag(),
makeLeaf(function<Complex(Complex,Complex)>
([_complex](const Complex x, const Complex y)
{return(_complex->tag
(_complex->makeFromRealImag(x,y)));})));
put("make-from-mag-ang",_complex->getTag(),
makeLeaf(function<Complex(Complex,Complex)>
([_complex](const Complex r, const Complex a)
{return(_complex->tag
(_complex->makeFromMagAng(r,a)));})));
}
//---------abstraction
barrier---------
const
Complex realPart(const Complex& z)
{return(applyGeneric("real-part",z));}
const
Complex imagPart(const Complex& z)
{return(applyGeneric("imag-part",z));}
const
Complex magnitude(const Complex& z)
{return(applyGeneric("magnitude",z));}
const
Complex angle(const Complex& z)
{return(applyGeneric("angle",z));}
template<typename
ReType,typename ImType>
const
Complex makeFromRealImag(const ReType& x,const ImType& y)
{
return(executable<Complex,Complex,Complex>
(get("make-from-real-imag","rectangular"))
(makeLeaf(x),makeLeaf(y)));
}
template<typename
MagType,typename AngType>
const
Complex makeFromMagAng(const MagType& r,const AngType& a)
{
return(executable<Complex,Complex,Complex>
(get("make-from-mag-ang","polar"))
(makeLeaf(r),makeLeaf(a)));
}
//---------abstraction
barrier---------
typedef
double Field;
ComplexProcedure*
_complexPackage1(nullptr);
ComplexProcedure*
_complexPackage2(nullptr);
const
void installRectangularComplexPackage(void){
_complexPackage1=new
ComplexRectangular<Field>();
activateComplexPackage(_complexPackage1);
}
const
void installPolarComplexPackage(void){
_complexPackage2=new
ComplexPolar<Field>();
activateComplexPackage(_complexPackage2);
}
const
void uninstallComplexPackages(void){
if(nullptr!=_complexPackage1) delete
_complexPackage1;
if(nullptr!=_complexPackage2) delete
_complexPackage2;
}
int
main(int argc, char** argv)
{
installRectangularComplexPackage();
installPolarComplexPackage();
const Complex
c1(makeFromRealImag(1.0,2.0));
cout<<"c1 =
"<<listString(c1)<<endl;
cout<<"(real-part c1) =
"<<listString(realPart(c1))<<endl;
cout<<"(magnitude c1) =
"<<listString(magnitude(c1))<<endl;
cout<<endl;
const Complex
c2(makeFromMagAng(1.0,M_PI/4.0));
cout<<"c2 =
"<<listString(c2)<<endl;
cout<<"(real-part c2) =
"<<listString(realPart(c2))<<endl;
cout<<"(magnitude c2) =
"<<listString(magnitude(c2))<<endl;
uninstallComplexPackages();
return(0);
}
----
出力
----
c1
= ('rectangular 1 2)
(real-part
c1) = 1
(magnitude
c1) = 2.23606797749979
c2
= ('polar 1 0.7853981633974483)
(real-part
c2) = 0.7071067811865476
(magnitude
c2) = 1
0 件のコメント :
コメントを投稿