2004-12-07 ========== xyzzy io-mode ------------- Reference URI: http://lowreal.net/logs/2004/12/07/1 Written Time: 2004-12-07T14:38:08+09:00 Tags: prog soft [io-mode.zip](/2004/io-mode.zip), [io-mode.l](/2004/io-mode/io-mode.l) 簡単そうなので作ってみる。殆ど c-mode のパクりなわけだけど……結局インデントレベル 計算するところしか作ってないわけで、そしてそれも括弧しか使わない Io では数えるだけ なわけで的な。とはいえアフォだからかなり詰ったんですけども orz ioServer の Regex て何か変じゃありませんか。nextMatch と firstMatch が全く同じ挙動 名気がする。つーかマニュアル書くなら効果的なサンプルと一緒に書いて欲しいなって思う 。戻り値も書いてないこと多すぎ。むしろ最初から String replace に正規表現とれるよう にしれと。正規表現がデフォで使えないとかキツすぎて死にます。 [io-mode readme](/2004/io-mode/readme), iolanguage iolanguage 引数のデフォルト値 ----------------------------- Reference URI: http://lowreal.net/logs/2004/12/07/2 Written Time: 2004-12-07T16:16:20+09:00 Tags: prog リファレンスを見た限りではメソッドの引数を省略したときの値を指定できないっぽい。よ うは可変長変数を使うんだと思うんだけど、これまた長い。んなわけで適当にマクロ化する メソッドを定義しとく。もしかしたらこんなことやらないでももっといい方法があるかもし れない。 /* pos : 引数の位置 name : 代入されるスロットのキー (勝手に初期化) default : デフォルトの値 */Object opt := method(pos, name, default, if (send er doString("thisMessage argAt(" .. pos .. ")")) then ( sender doString(na me .. " := sender doMessage(thisMessage argAt(" .. pos .. "))") ) else ( sender setSlot(name, default) ))んで以下のように使う。 List join := method( opt(0, "sep", "") ret := "" self foreach(index, val ue, ret = ret .. value if (index < self count - 1) then ( ret = ret .. sep ) ) ret)l := List clone push("aaa") push("bbb") p ush("ccc")l join(", ") print //=> "aaa, bbb, ccc"l join print //=> "aaabbbccc"Ruby の Array#join っぽいことをしてみる。 String join というメソッドがあるけど何か このメソッドは位置がおかしいし、セパレータを引数にとれない。っぽい というのはデフォルト引数が "" きめうちだから。Io に $, がないから (なくていい) ってことです。あーあと再帰的に join してないや。to_s メソッドとかないからその辺もやってないし。 ようは List の中身が String 以外だと例外はきますよと。 どうでもいいけど if を書くときに then と else を使うのは構造的違和感がある。でも可読性はこっちのほうがいいし、case がないうえに if の引数として書く場合 elseif が書けないからどっちにしろ書くことにはなるんだけど。if の引数に全部書くほうはワンライナー向けかしら。 iolanguage Directory items -------------------------- Reference URI: http://lowreal.net/logs/2004/12/07/3 Written Time: 2004-12-07T21:14:33+09:00 Tags: prog 何で Directory が ioServer なのかはとりあえず置いておいて、Directory items が File しか返さない。Returns a list object containing File and Directory objects ですよ。*1 いや英文解釈が間違っているのかもしれないとか思いつつしかし常識的に考えて (まぁたし かに Directory も File ではあるけど) Directory を File として返さないだろうとか、 むしろ File としてしか返さなくて File にタイプを識別するメソッドがなかったら使えな いよねって思ったから File にそんなメソッドあるのかなって思ったらなかった。そういや File Primitive にはファイルの更新時間を取得するメソッドもない気が。つまるところ今 のデフォルトの Io では blosxom クローンは作れないっぽい。 てか Regexp, Directory を IoVM の Primitive に…… iolanguage メソッドの引数の評価 ------------------------------- Reference URI: http://lowreal.net/logs/2004/12/07/4 Written Time: 2004-12-07T22:19:20+09:00 Tags: prog 素朴な疑問にひっかかった。if とか else もメソッドで、引数にメッセージをとるけど、 何でこの引数は評価されずに渡されるんだろう。ちょっと解りにくいから実際にコードを書 いてみる。 if (Nil) then ( "not print" print) else ( "print" print)この場合もちろん not print は出力されないし、それが願う動作。しかしながら "not print" print も引数だから、メソッドに渡される前に評価されて not print と出力されるんじゃないかと悩んだ。というか正確に言えば if をユーザから定義すると きに評価されてしまってハマった。以下にハマったコードを示す myif := method(test, ifObj := Object clone ifObj test := test ifObj do ( mythen := method(msg, if (test, sender doMessage(thisMessage a rgAt(0))) self ) myelse := method(msg, if (te st isNil, sender doMessage(thisMessage argAt(0))) self ) ))m yif (Nil) mythen ( "nil" print) myelse ( "aaa" print)これは予想に反して nilnilaaa と出力される。引数が渡される前に評価されしまっているからだ。リファレンス見てても よくわからないので、適当に書き直していたらできた。書き直した結果を書いてみる。 myif := method(test, ifObj := Object clone ifObj test := test ifObj do ( mythen := method( if (test, sender doMessage(thisMessage argAt (0))) self ) myelse := method( if (test isNil , sender doMessage(thisMessage argAt(0))) self ) ))何が変わったかっていうと method の仮引数を書かないようにしただけ。仮引数を書くと評 価されてしまうらしい。微妙な罠。プログラミングガイドに明記してもいいじゃん! とは いえこれを踏まえてから読み直すと The thisMessage slot that is preset (see next section) in locals can be used to a ccess the unevaluated argument messages. と書かれていて*2 (強調はされていない) 頭がよければ thisMessage スロットには未評価なメッセージが入 っていて、仮引数を書かなくても呼び出せる。もしかして仮引数を書かなければメッセージ は評価されないんじゃないか、なんて推論できる (苦しい) かもしれないけど、俺には無理 !