トップ «前の日記(2008-01-06) 最新 次の日記(2008-01-08)» 編集

Route 477



2008-01-07

[biwascheme] write_ssを実装した

相互再帰関数の実行をデバッグしようとしたら、循環構造を文字列化しようとして無限ループになることが分かったので、 write/ssのようなものを実装した。

gosh> (let ((x (list 'a))) (list x x))    
(#0=(a) #0#)

こういうやつ。「#n=」で名前を付け、「#n#」で参照する感じ。

どうやればいいか分からなかったので、とりあえず2パスで実装することにした。

  1. まずダンプしたいオブジェクトを再帰的に辿り、複数回出現するオブジェクトを全てメモする。
  2. このメモを見ながら、オブジェクトを再帰的に文字列化していく。
    • 2度以上出現するオブジェクトで、初回の出現なら、#n= を頭に付ける。
    • 2度以上出現するオブジェクトで、2回目以降の出現なら、単に #n# と出力する。

とりあえずletrec*を使ったコードのデバッグに使ってみたら、こんなんが出てきて吹いたw

#0=[[#1="frame", [#1#, [#2="constant", #3=1, [#4="argument", [#5="refer-local", #6=0, [#7="indirect", [#4#, [#8="refer-global", #9="-", [#10="apply", #11=2]]]]]]], [#4#, [#12="refer-free", #6#, [#7#, [#10#, #3#]]]]], [#4#, [#2#, #3#, [#4#, [#8#, #13="+", [#14="shift", #11#, #3#, [#10#, #11#]]]]]]], [[[#1#, [#5#, #6#, [#7#, [#4#, [#8#, "zero?", [#10#, #3#]]]]], ["test", [#2#, #6#, ["return", #3#]], [#1#, [#1#, [#2#, #3#, [#4#, [#5#, #6#, [#7#, [#4#, [#8#, #9#, [#10#, #11#]]]]]]], [#4#, [#12#, #3#, [#7#, [#10#, #3#]]]]], [#4#, [#2#, #3#, [#4#, [#8#, #13#, [#14#, #11#, #3#, [#10#, #11#]]]]]]]]], [#15=#<undef>], [#0#]]], [#15#]]

あー、数値はimmutableだからタグ付ける意味ないのか。 (readしたときに同型の構造ができる、ってのがこの表記の目的らしいので。) 文字列もJavaScriptレベルではimmutableなんだから タグ付けるのやめようかなぁ。

Gaucheの場合

write.cを見てみたけど、Gaucheも2 passなんだな。

/* We need two passes to realize write/ss.

   The first pass ("walk" pass) traverses the data and finds out
   all shared substructures and/or cyclic references.  It builds a
   hash table of objects that need special treatment.

   The second pass ("output" pass) writes out the data.

ただ、発見したオブジェクトのテーブルは配列じゃなくハッシュテーブルを使ってるらしい。 そりゃそうか。