こんにちは、@tomoodaです。
今まで書きたいことは基本的にtwitterに書いていましたが、やっぱり文字数制限がつらい。ツ コード例とか書くだけでももう大変。それがブログなら
(PGeneGenerator on: [ :g | | i j | i := 0. g yield: i. j := 1. g yield: j. [ i + j =>> [ :k | g yield: k. i := j. j := k ] ] repeat ]) =>> [ :fibonacci | 10 timesRepeat: [ Transcript cr; show: fibonacci next printString ] ]
がはははは、余裕で書き下せるぜい!勝ったも同然。なお、上記のコードはPharoというSmalltalk処理系でフィボナッチ数列を10個、トランスクリプトウィンドウに表示します。
Smalltalkerにも見慣れないモノがあると思いますが、これは開発中のPGeneというライブラリが実装するジェネレータPGeneGeneratorの例題です。Pythonのジェネレータがあまりにも便利なので、ついSmalltalk上で実装しちゃいました。
Smalltalkには昔からStreamクラスがあり、nextメッセージを投げる毎に次の値を返してくるのですが、いかんせん数列を定義する度にクラスを定義したのでは、「だからクラスベースは…」などと言われてしまいます。
また、Smalltalkには昔からdo:メッセージもあり、クロージャを渡して繰り返し評価をします。しかし悲しいかな、do:はファーストクラスオブジェクトではないのです。複数のオブジェクトから次から次へとnextメッセージを投げるような自由度はありません。
そこでジェネレータです。nextメッセージを受け取ったら、クロージャ[:g | ... ]を評価します。そして、クロージャを評価していく中で、使いたい値が手に入ったらいつでもyield:メッセージを投げれば、その引数がnextメッセージの返り値となります。また、次にnextメッセージを受け取ったら、前回yield:した箇所から実行を再開して、次のyield:がnextの返り値になります。まあ、なんて便利なんでしょう。ツ このように2つの実行コンテキストを交互に継続させることをコルーチンといいます。
Smalltalkは実行コンテキストまでファーストクラスオブジェクトなので、この程度のことはフフンのフンなのです。ツ
次に見慣れない表記は=>>でしょう。一般には、expr =>> [ :name | ... ]という形で使って、exprの評価結果にnameという名前をつけて、...を評価します。これがあると何が嬉しいかと言うと、自然とローカルなスコープになるだけでなく、破壊代入と名前束縛を明示的に分離できるのが最大の利点です。Smalltalkは関数型言語でも論理型言語でもないので、破壊代入は悪ではありません。しかし、濫用せずに、弊害を最小化しながらそのメリットを享受しようじゃないですか。ツ ちなみに、実装としては=>>の左側のオブジェクトを引数にして右側のクロージャを評価しているだけです。
こんな調子で、Smalltalkのこと、オブジェクト指向のこと、プログラミングのこと、その他いろいろ書いていきます。
よろしく! ツ
0 件のコメント:
コメントを投稿