メインの言語がオブジェクト指向言語中心だから、データと手続きが一体になっていないと何となく収まりが悪い気分になるが、module をパラメータ化すればクラスっぽく定義する事もできるらしい。
-module(rational, [Numer, Denom]). -compile(export_all). numer()->Numer. denom()->Denom. new(Numer,Denom)-> Gcd=integer:gcd(Numer, Denom), instance(round(Numer/Gcd), round(Denom/Gcd)). add(R)->new(numer()*R:denom() + R:numer()*denom(), denom()*R:denom()). minus(R)->new(numer()*R:denom() - R:numer()*denom(), denom()*R:denom()). multiply(R)->new(numer()*R:numer(), denom()*R:denom()). divide(R)->new(numer()*R:denom(), denom()*R:numer()). to_string()->integer_to_list(numer()) ++ "/" ++ integer_to_list(denom()). to_float()->numer()/denom().
試しに上のような簡易実数クラスを書いて実行してみた(integer:gcd()は別のモジュールで定義したGCD関数。同じモジュールで定義するとコンストラクタから呼べなかった)。
17> R_1_2=rational:new(1,2). {rational,1,2} 18> R_1_3=rational:new(1,3). {rational,1,3} 19> R_1_2:add(R_1_3). {rational,5,6} 20> R_1_2:minus(R_1_3). {rational,1,6} 21> R_1_2:multiply(R_1_3). {rational,1,6} 22> R_1_2:divide(R_1_3). {rational,3,2} 23> (R_1_2:minus(rational:new(11,13))):to_string(). "-9/26" 24> (R_1_2:divide(rational:new(100,1))):to_float(). 0.005
まあこんな感じか。コンストラクタに小数点数が来たときとか分母に0が来たときとかのちゃんとした実装はとりあえず省略。このPDFを見ると、継承のやりかたなんかも書いてある。割と簡単そう。
ただ、せっかくErlangをやってるのに、何が悲しくてこんなコード書いてるのかと、釈然としない感じも残る。本当は、オブジェクトとして考えるのを一旦止めて、改めてプロセスとして捉えなおすようなパラダイムシフトが必要な気がしないでもないが、まあもう少し勉強しないとダメだな。
0 件のコメント:
コメントを投稿