Syntax highlighter

2011-03-25

syntax-rules再び

レコード、コンディションができて、with-exception-handlerも上手いこと動いていそうな感じだったので、
Ypsilonにあるguardの実装を試してみようとおもったら、パターンマッチでエラーがでた。
具体的にはこんなパターン。
;; guardの実装で使われていたものの一部
(define-syntax hoge
  (syntax-rules (else)
    ((_ (var clause ... (else clause2 ...)) b1 b2 ...)
     (do-something))))
エラーとしてはellipsisが足りないらしい。

元々はMIT Scheme由来のものだったので、とりあえず本家でも試してみたが、こけた。一応moshでも試してみたがOKだったので、R6RS的にはOKなんだろうと推測。
ということは、足りない部分を補うか、新たに何とかするしかないということだ。ここは一発気合をいれて実装してみようと思い、まじめに仕様を読むことにした。
要求されているのは以下のとおり。

  • P が下線(_)である場合
  • P がバターン変数である場合
  • P がリテラル識別子であり、マクロの出力に挿入される識別子以外で P と F が両方ともマクロ出力に現れたとき、 F が P と同一の束縛を参照している場合(ふたつの名前風の識別子がどちらも何の束縛も参照しないない場合、すなわち、どちらも未定義である場合も、両方とも同じ束縛を参照しているものと考える)。※1
  • P が (P1 ... Pn) の形式でF が n 要素のリストで P1 から Pn に一致する場合
  • P が (P1 ... Pn . Px) の形式で F が n 要素以上のリストないしは非真正リストで、最初の n 要素が P1 から Pn に一致し、 n 番目の cdr が Px に一致する場合。
  • P が (P1 ... Pk Pe <ellipsis> Pm+1 ... Pn) の形式で、 <ellipsis> が識別子 ... で、かつ F が n 要素のリストで、最初の k 要素が P1 から Pk に一致し、 次の m - k 要素が Pe に一致し、残りの n - m 要素が Pm+1 から Pn に一致する場合。
  • P が (P1 ... Pk Pe <ellipsis> Pm+1 ... Pn . Px) の形式で、 <ellipsis> が識別子 ... で、かつ F が n 要素のリストないしは非真正リストで、最初の k 要素が P1 から Pk に一致し、 次の m - k 要素が Pe に一致し、残りの n - m 要素が Pm+1 から Pn に一致し、最後の n 番目の cdr が Px に一致する場合
  • P が #(P1 ... Pn) の形式で F が P1 から Pn に一致する n 個の要素のベクタである場合
  • P が #(P1 ... Pk Pe <ellipsis> Pm+1 ... Pn) の形式で、 <ellipsis> が識別子 ... で、かつ F が n要素以上のベクタで、その最初の k 要素が P1 から Pk に一致し、次の m - k 要素がそれぞれ Pe に一致し、残りの n - m 要素が Pm+1 から Pn に一致する場合
  • P がパターンデータ(リスト、ベクタ、シンボル以外のデータ)であり、 F が equal? 手続きの意味で等しい場合
syntax-caseの方も※1以外は一緒であった。
基本的なパターンマッチの部分は同じで細かい違いは別にすればなんとかなりそうだろうか。

moshはよく知らないが、YpsilonとGaucheはsyntax-rulesで現れたパターンを一度コンパイル(後でパターンマッチがしやすいように情報を集めておくという意味)して、マクロが使用された際にその情報を元に展開していくという方法を取っている。
それとは別にMIT SchemeやChibi Schemeではsyntax-rulesが現れたらそれ自体をS式を返すS式に変換し、展開時には元のS式をマクロ展開用のS式(要するに展開器)に食わせている。
前者はマクロを展開するコンパイラが展開方法を知っていないといけないが、後者はマクロを展開するタイミングだけ知っていれば後はマクロが勝手に展開してくれる。現状Sagittariusは後者の方法を取っている。(なので、Sagittariusには組み込みのマクロというのはない。マクロはS式とコンパイル時の環境をペアで取るλ式に過ぎなかったりする)

とりあえず、パターンの部分の解析からはじめてみよう。

2011-03-22

R6RSのレコード

例外機構を入れようと思ったら、避けて通れなかったので先に実装することになった。
(with-exception-handlerはすでに作ったのに・・・)

とりあえず、仕様書を読むもよく分からん。Ypsilonの実装がかなりシンプルでいい感じなのでそれを参照することにする。
まずは動作確認。
この段階でとりあえず気づいたこととしては、レコードの中身はtupleみたい。
ちなみに、Ypsilonのtupleはかなり気が利いてる仕様で、見た目は単なる配列なんだけど、先頭要素に「type:」ってついたシンボルを指定すると出力時に「type:」以降だけを出力してくれる。あたかもそれが組み込みの型かのように。
話がそれた。実際に(tuple? (make-warning))とすると真を返してくるので、間違いないだろう。

ここで問題になるのはSagittariusにはここまでシンプルかつ高機能な配列はないということ。Generic&Instanceなんて無駄にごてごてした機能はあるんだけど、こいつを使えばいいかな。
とりあえず、やってみるか。

2011-03-18

Dynamic-windがほしい

テストしながらやっているとどうしても例外を捕捉する機構がほしくなる。
というのも、定義ファイルに書いた組み込み関数の中身が間違っていたとき、現状だと例外を投げて、スタックトレースを出力して落ちる。スタックトレースにある程度どこで起きたのか書いてあるんだけど、直して走らせたら次が出てきたときにがっかりする。
そもそも、単体テストを走らせてるのに、テスト中に落ちるのはあまりに不都合な気がする。ここは一発Dynamic-windを実装して、guardとraiseの実装かね。次の目標にしよう。
(算術用の関数がまだ終わってないけど、一段楽したし)

例外周りを整備するということは、今適当に投げてる例外をちょっと整理しないとなぁ。R6RS的には例外はいくつかの階層を持ってるみたいだし。その辺も考えないと。本当に先が長い。

2011-03-17

なんだか本体以外が充実していく

本体が全然進まないのに周りが進んでいく感じだ。

とりあえず横道にそれた便利ツールとして、
  • VMインストラクションの定義から実装を自動生成する仕組み
  • 簡単なユニットテストフレームワーク
一つ目のはいずれやろうと思っていたが、いろいろ行き詰っていたのでえいやっとやってしまった。もともとcgenがあったのでちょいちょいと定義を足すだけであった。(それ以外にも多少の改修があったが)
これをやったおかげでDirect Threaded Codeの実装が簡単にできそうだったのでついでに実装。どれくらい早くなったのかは分からないけど、とりあえずGaucheとの速度比較。
マシンスペック: ThinkPad X60 Core Duo 1.6GHzくらい?
ベンチマークプログラム: たらいの12, 6, 0
結果:
$ time ./build/sash.exe test3.scm
./build/sash.exe test3.scm 3.52s user 0.01s system 98% cpu 3.601 total

$ time gosh test3.scm
gosh test3.scm 2.91s user 0.01s system 99% cpu 2.934 total
以前と思うと少し差が縮まったか?(でも、以前はGCCの最適化オプションをデバッグのために切ってたから微妙かも)

二つ目のはコンパイルするたびに何かしら(今のところR6RSのライブラリだが)を足していたのだが、いちいち目視で確認するのがイヤになったので、簡単なのでいいから作るかと思って作った。最初は完全R6RSの範囲内で書けるようにしてたけど、諸事情によりSagittarius(というかexplicit renamingに)依存になってる。
一応機能としては、テスト結果と失敗したテストを表示する(そのままは表示されないけど、数値とか)

あと、bitwiseな計算とかがちらほらサポートされたかな。
syntax-caseの実装をとりあえず後回しにして、進められそうなところから進めてる。しかし、R6RSは標準のライブラリがかなり巨大で実装にちょっと辟易してきた・・・orz
でも負けないもん!!

2011-03-07

マクロのシグネチャを変更

(書いてたのが手違いで消えたので2回目。萎える)

define-syntaxが取る式のシグネチャを変更した。今まで2つの引数を必要としていたのに対し、1つの引数を取ることにした。ただ、S式とコンパイル時環境のペアにしただけではあるが、明示的に何が来ているのか分かりにくくなったというデメリットもある。まぁ、生のマクロをいじることはそうないだろうと思うのであまり関係はないが。

これに伴って、今まで構文キーワードだったer-macro-transformerが単なるクロージャに格下げ(?)となった。これはchibi-schemeで実装されていたマクロ変換器からアイデアをもらっている。

これらの変更をしていたので全然syntax-caseの実装が進んでいないが、パターンの解析、マッチング部分の構成、出力部の構成はsyntax-rulesの実装が流用できると思っている。問題となるのは、syntax-caseは構文オブジェクトを返す必要があるということ。
構文オブジェクト自体はあるのだが、それが返っても今の段階ではなんの意味もない。その辺を考える必要がある。

しかし、syntax-rulesが動くので、どっかからexpander(psyntaxとか)を拾ってきてしまおうかという誘惑に駆られる。いかんいかん。

2011-03-05

マクロの問題

syntax-caseを実装していて困った問題に気づいた。
問題の本質を指すコード
(define-syntax hoge
  (lambda (x)
    (er-macro-transformer
      (lambda (form rename compare)
        (display x)
        `(display ,form)))))
一見特に問題ないように見えるが、ここで「x」はer-macro-transformerからは見えない。理由はいたって簡単で、er-macro-transformerの後ろに来たλ式は、それだけでコンパイルされるからである。でも、S式から中間式に変換する段階では見えているので、「x」は大域変数としては扱われない。束縛変数か、自由変数から探そうとしてこける。

実装の問題になると思うのだが、Sagittariusではdefine-syntaxというキーワードはマクロかクロージャのどちらかを取る様にしてある。(以前は何でも取れた)
こんなのでも、特に問題なく動く。
(define-syntax hoge
  (lambda (a b c d e)
    (+ a b c d e)))
(hoge 1 2 3 4 5) ; -> 15
おそらくこの辺が問題なのだと思う。
(ちなみに、クロージャが取れるようにしたのはsyntax-caseを実装するためにこの構文が必要だっただけ)
syntax-rulesもライブラリで実装している今、まじめにdefine-syntaxについて何か考えるときなのかもしれない。

R6RSでこれが問題ないならあんまり気にしなくてもいいのに↓
(define-syntax hoge
  (syntax-case ()
    ((...))))
あぁ、でもこれじゃwith-syntaxの実装とかできなくなるのね。というか、syntax-caseってそれ自体はたんなるマッチングみたいなのか、引数取るし。

syntax-case、かなりいいところまで行ったような気がしたけどやり直しだ・・・

2011-03-04

syntax-caseの実装

結局MIT Schemeのsyntax-rulesの実装を移植して現在syntax-rulesとsyntax-caseを実装中。
syntax-rulesはYpsilonのストレステストが動かないが(正しくマクロのマッチングが行われない)、まぁ通常用途には使える程度に動いてる。
っで、syntax-caseなのだが、とりあえず、動作結果を確認するために以下のようなものをYpsilonに喰わせてみた。
(import (rnrs))

(define-syntax fuga
  (lambda (x)
    (syntax-case x ()
      ((_ r ...)
       (begin
  (display x)(newline)
  (syntax
   (list '(r (r ...)) ...)))))))
(display (macro-expand (fuga 1 2 3)))
で、結果はこんな感じ
(fuga 1 2 3)
((1 (1 2 3)) (2 (1 2 3)) (3 (1 2 3)))
これが意味するところとしては、マクロ内で定義された構文オブジェクト意外はマクロ展開時に実行されているということ。
っで、macro-expandの部分を%macroexpandに変更してSagittariusにも喰わせてみると。こんな感じ。
(begin
 (display x)
 (newline)
 (#<syntax list>
  (#<syntax quote> (1 (1 2 3)))
  (#<syntax quote> (2 (1 2 3)))
  (#<syntax quote> (3 (1 2 3)))))
ここから察するに、もう一段階実行してやって、構文オブジェクトで包まれてる部分を取り除いてやればよさそうだ。
問題はいくつかあって、
  • コンパイラは構文オブジェクトを見つけた際に、(組み込みかユーザー定義かの差はあるが)マクロ展開を行おうとする
  • もう一段階実行した際に、構文オブジェクト以外の部分がコンパイル実行されるため、たとえばシンボルをリストにしようとした際にVMがエラーを通知する
とりあえず、思いつくだけで2つか。まだありそうだが。前者はコンパイラに(また)条件式を追加する必要がある。(いやだなぁ)
後者はどうしようかねぇ。考えるか。

2011-03-02

プロジェクトホスティング

GoogleのCode Hostingサービスを利用しだした。
まだ、0.0.1にも届いていないが、ちょっと不便になってきたので。
場所はここです。興味があれば。
名前はSagittariusです。

未だにsyntax-caseの実装に戸惑っているが、とりあえず、組み込みのマクロはexplicit renaminig一本にして、syntax-rulesもライブラリとして提供するようにした。
おかげで、マクロ(syntax-rules)使うとコンパイルが遅いが・・・まぁ、それはそのうち何とかしよう。

基本的にsyntax-rulesのパターンマッチとsyntax-caseのパターンマッチは同じなはずなので、流用できるのではないかと考えている。
っが、Sagittariusのdefine-syntaxは与えられたフォームを特に構文オブジェクトにラップするということをしないので、(syntax '(let ...))とかって構文が困るんだよね。というか、syntax->datumとかdatum->syntaxとかその辺にかかわる手続きをどうしようかなぁと。syntax-case構文内だけで使うってことなら、er-macro-transformerのcompareとかrenameをごにょごにょすればいいかなとかも思うけど、そうもいかないよなぁ。

そうそう、
かっちょいいロゴ作ってくれる人募集中です。
あと、syntax-caseを実装してくれる方も絶賛募集中ですw

2011-03-01

まぁここは英語圏ではないのだが

Island Life - [i]と[iː] を読んでちょっと思ったこと。(1年前の記事だが)

[i]と[iː]の発音の癖が抜けない。つい、「イ」と「イー」で発音してしまう。実際は、音の長さではなく、[i]の方が「イ」と「エ」の中間、というかゆるい感じで、 [iː]は緊張した「イ」なんだけど、知識として知っててもうまく出てこない。

個人的に[i]と[iː]の違いは長母音と短母音の差だと思う。BBC Learning Englishにきっちりshort vowelsとlong vowelsに分けられているので。
少なくとも、上記のBBCから辿れる発音の講座で見られるビデオでは長いか短いかくらいしか差がないような気がする。
(個人的にイとエの中間は、eを逆さにした記号で表されるやつ(schwa)だともう。これは弱母音なので、慣れるまで発音が激ムズだった。日本語にない母音だし。あ、これはアとエの中間か?)

ここからは、単に僕の経験からなのだが、アメリカンとブリティッシュで母音の発音がかなり違うと思う。
(まぁ、聞けばすぐ分かるレベルでいろいろ違うので、言うまでもないのだが)
こっちに来てから毎年のようにフロリダに旅行で行っているのだが、そこでは、以前にも書いたが、僕の英語は割と通じない。それは、アメリカ人が自分たちの訛しか理解しないだけではなく、僕の話す英語がアメリカンではなくなってきていることにもあるのかもしれない。
(と言って、ブリティッシュというわけでもないが)
例えば、「hot」はこっちではそのまま「ホット」で通じるがアメリカ(南部訛?)だと「ハット」に近い感じにしないと店員さんは分かってくれない。
(前にも書いたなこのネタ)

そもそも、多国籍な会社で共用語として話される英語なので比較にならないが、正直だれもそんな発音の違いをつけてないと思う。ロンドン出身のイギリス人も会社にいるが、fishを「ふぇっしゅ」に近い発音で喋るようには聞こえないなぁ。

話がまとまらなくなってきた。結局言いたいことは、ここでは[i]と[iː]の違いは短いか長いかの差だということです。

2011-02-28

SHA BU SHA BU

こんな名前のレストランがオランダにはある。
名前の由来はもちろん日本のあの料理だ。実際、レストランのサイトには名前の由来はその料理からとったと書いてある。
さて、ここで問題。あなたは日本人(まぁ、ほぼ100%そうだと思うけど)だと仮定します。あなたはこの料理の詳細を知っています。そしてそのレストランを見ました。このレストランの看板メニューを答えなさい。(30点)


・・・


・・・・・・


・・・・・・・・・


時間切れです。あなたの答えは何だったでしょう。まぁ、こんな聞き方をしているのだから、まさか「しゃぶしゃぶ」なんて安易な答えじゃないですよね。
ちなみに、答えは寿司です!!

おかしいだろ!!!どう考えても!!!
久しぶりにしゃぶしゃぶだぁなんてはしゃいで予約いれて、HP見たら寿司がメインかよ!!即行キャンセルだぜ。
とりあえず、中国人経営日本食レストランの寿司は大抵はずれだからというのと、腹具合がいい感じにしゃぶしゃぶ用にセッティングされてたからな!!
お前それ、「四川料理」って銘打ってるのに「北京ダック」だすようなもんじゃね?

他にもいろいろ「KIMONO」とか「SUMO」とか「SAKURA」とか(まぁ桜はいいか)、突っ込みどころが多い名前のレストランがあるが、今回のは食べる前から壮大に裏切られた。

ちなみに、どうしてもしゃぶしゃぶが食べたかったので、自分で作ったとさ。
(牛肉の薄切りが売ってる日本っていいなぁと思いながらね・・・)

2011-02-24

er-macro-transformerでsyntax-caseを実装

まだ使用としているだけだが、とりあえずChibi Schemeのsyntax-rulesが動いた。
以前書いた問題は意外と簡単で(といっても、実装の核にかかわる部分の違いだったので判明するのに少し時間がかかったが)、identifier?の判別の差だった。
Chibi Schemeではidentifier?はsymbolもしくはsyntactic-closureのどちらかも満たすものなのだが、僕の実装系にsyntactic-closureはない。またidentifier自体が一つのScheme型として存在してるので、渡された生S式から取り出したものと、renameされてidentifierに変換されたものとの比較が上手くいってなかった。
とりあえず、compare関数に渡す際にすべてrenameすることにしたが、多分これはcompare関数自体を変更した方がよさそう。現状だと単にeq?で比較なので、symbolとidentifierの比較は確実に偽になる、でもそれだと不便すぎる気がするので、わたってきた値がsymbolとidentifierの混在だったらrenameしてから比較した方がいい気がする。

この実装のいいところ(?)は(おそらく、まだ全部試してないので)srfi 46をデフォルトで実装しているところだと思う。でも、組み込んであるGauche由来のsyntax-rulesに比べるとすごく遅い。おそらく、希望的観測だが、コンパイルが遅いのだと思う。展開は速いと信じたい。(明日試す)
何とか高速化できたら、組み込みのsyntax-rulesをやめてこっちを採用したい。特に意味はないが、組み込みのマクロはer-macro-transformerだけで、残りはライブラリという位置づけにしたい。
問題は、今のところマクロはCに書き出すことができないところか。多分できなくもないんだろけど、やるなら、ちょっと(大分)考えないと。

これを足がかりにsyntax-caseが実装できたら、後は必要なライブラリをそろえるだけ。バージョン0.0.1のリリースも近いか。

2011-02-23

招待状

大学の後輩(とってももう直接のかかわりは無いが)から定演の招待状が届いた。
海外にも送ってくれるのはとても律儀で好感がもてる。
っが、今週末に開かれる演奏会に、今日届いていては招待する気がないとしか思えない。
届くまでに一週間かかったとしても、送ったのが2月14日の週では遅すぎないかね?

っと、こんなところ彼らが見ているわけもないだろうので、あまり意味は無いが。
ま、ちょっとした愚痴です。
(しかし、マジで行く気で3月にチケットとってたら張った押したくなるくらいの仕打ちだわ)

2011-02-21

与太話

変換したらこれだったけどいいのか?

皆さんはヨーロッパにどんなイメージをお持ちだろうか?例えばこんなのは僕が昔持っていたイメージ。
  • お洒落
  • 金髪美男美女ばかり
  • スーツ着てビジネス
  • モダンな建物
  • 歴史のある風景
  • 陸続きなんだから、2,3ヶ国語は当たり前
もし皆さんがそのような幻想をお持ちなら
                ヘ(^o^)ヘ ok.
                  |∧  
               /  /
           (^o^)/ If you are confident in
          /(  )    what you can, do everything you wish,
    (^o^) 三 / / >
\    (\\ 三
(/o^) < \ 三 
( /
/ く  I would destroy
      your fuck'n fantasy. 
(単にこれを言いたかっただけ)

さて、順番に幻想を壊していきましょう。と言っても、オランダとベルギー、あとフランスの少しくらいしか知らないので、イギリスは違うとか、ドイツはもっとこうだといわれても反論はできません。突っ込みは大歓迎です。

【お洒落】
待ち行く人々を指すなら、日本人の気合にかなう国はそう多くないでしょう。こっちなんて化粧すらあんまりしてない気がします。男も女も基本ジーンズです。

【金髪美男美女ばかり】
そもそも、移民の歴史があったり、アフリカから奴隷をつれてきた歴史があるので、金髪だけではありません。(ラテン系の人は黒髪だし)。美男美女ばかりでもありません。容姿の偏差値というのは変な感じですが、日本が45~60くらいの間だとしたら、30~70とか幅がある感じです。男は基本掘りが深くて毛深いです。でも、頭髪は意外と少ないので禿がマジで多いです。女性へのコメントは控えます。

【スーツ着てビジネス】
これが意外と北米とかでも勘違いされてると思われる事項です。とりあえずオランダだとスーツ着る人いません。一応商談があるとか会社の偉い人は着てますが、普通の社員はジーンズでOK。楽なもんです。昔カナダにワーホリで行った時のホストマザーが、北米の東の方(モントリオールとか、ニューヨークとか)はヨーロッパ色が強く、ビジネスではスーツが基本、時間に厳しい、なんて行ってましたが、完全に妄想です。少なくともオランダでは。

【モダンな建物】
ニュータウンとか、ビジネス色の強い地域じゃないとそんなもんありません。アムステルダムなんて歴史を感じる建物ぐらいしかないです。まぁ、南駅まで出ればビジネス色のほうが強いので、ワールドトレードセンターとかありますが。僕の働いているロッテルダムはどちらかといえばモダン色が強いですが、やっぱりそうでもないです。

【歴史のある風景】
これは本当。ちょっと有名な都市(ライデンとか)だと歩けばそこに歴史があります。まぁ京都みたいな感じです。ま、そうは言っても古めかしい建物の隣にマクドナルドがあったりとか普通なので、あんまり歴史を感じないかも。

【陸続きなんだから、2,3ヶ国語は当たり前】
人によります。まぁ、そうは言っても英語は大抵の人が喋れると思います、がそれを期待すると裏切られることが多々あります。ヨーロッパの中では一番きれいな英語を喋るという風評があったのですが、1年前くらいにイギリスだかどこかが調査した結果、そうでもないということが実証されたそうです。まぁ、アクセントというか訛はありますね。人の事言えませんが・・・

この中に当てはまる幻想があって、見事に砕かれたならもうヨーロッパなんて怖くありません。(何かを恐れてたのか?)

2011-02-18

syntax-caseをexplicit renaming macroで実装するには

どうしたらいいのだろう?

自前の処理系にはer-macro-transformerがある。というか、R6RSに準拠することをとりあえずの目標にしているのだが、syntax-caseを実装するのが(個人的に)無理だったので、(まぁ、psyntaxとか他のexpanderに頼ってもよかったのだが)、とりあえず、explicit renaming macroを実装して、それを使ってsyntax-caseを実装するという手をとろうと考えたわけだ。
正直、ここまでは悪くない手だと自分では思っている。Gaucheの川合史朗さんのBlogのエントリーにsyntax-case、explicit renaming macro、それ以外の衛生的マクロ(Syntactic Closureとか)のどれか一つがあれば他のマクロはポータルに実装できるとあるので、後はその実装だけかなぁとは思ってたりするのだが、いかんせん頭が足りない。
Chibi schemeにer-macro-transformerを使ったsyntax-rulesの実装があってそれをとりあえず走らせて見たのだが、どうも動きがおかしい。
例えば、以下のコード
(define-syntax test
  (syntax-rules ()
    ((_ o)
     (display o)
     (test)
    ((_)
     (newline))))
(test 'a)
(今ちょっと思い出して書いただけなので、間違いがあるかも)、通常のsyntax-rulesなら実行結果は単に「a」と改行をプリントするのだが、Chibi scheme由来のsyntax-rulesを自前の処理系で走らせると、「unbound variable o」となる。
実際、VMのインストラクションを吐かせてみたら、
;; 略
GREF_PUSH o          ;; グローバル変数oに束縛された値をスタックに積む 
GREF_CALL(1) display ;; displayをコール
;; 略
なんてことになってて、そりゃ「o」なんてどこにも定義してないからなぁと納得はするのだが、どうしてそうなるのかさっぱり分からない。
マクロを展開を試してみて、途中でこける。途中のどこかがおかしいので空のリストがcarに与えられてこける。
Chibi shcemeのsyntax-ruleの基本的な感じとしては、(まじめに追ってないので本当に感じ「feeling」だけだが)、er-macro-transformerでer-macro-transformerを作るといった処理に見える。
あれ、ちょっとまてよ、もしそうだとした、こんな感じのマクロが
;; something-macroは別のとこで定義
(define-syntax a
  (something-macro ()
    ((_) (do-something))))
こんな感じに
(define-syntax a
  (er-macro-transformer
    (lambda (form rename compare)
      ;; パターンマッチングの処理とかがあって、最終的に
      ;; これ↓を呼ぶ
      (do-something))))
展開されるということか?
でも、自前の処理系だと、マクロの展開は、マクロのコンパイル → コンパイルされたコードの適用 → 展開されたコードのコンパイル、という実行順序なので、2段階コンパイルされるということになる。1段階目でコンパイルされた時は参照(というか変数?)だったシンボルが、2段階目では変数として扱われてるということかな。
なんかちょっと見えてきたかも。試してみよう。

2011-02-10

とりあえず竹内関数を動かしてみた

まだ足りないところが多いが、たらい回してみた。
ソース:
(define (tarai x y z)
  (if (<= x y) y
      (tarai (tarai (- x 1) y z)
      (tarai (- y 1) z x)
      (tarai (- z 1) x y))))
(display (tarai 12 6 0))
Cygwinのtimeコマンドで一応ほかの処理系とも比較してみた。
(この段階で速度的に勝てるとは思わん!!)

結果:
自分の
→ 2.62s user 0.00s system 100% cpu 2.607 total

Gauche
→ 0.01s user 0.00s system 1% cpu 0.814 total

Ypsilon
→ 0.01s user 0.00s system 1% cpu 0.755 total

mosh
→ 0.80s user 0.03s system 101% cpu 0.812 total

見方が間違ってなければこの段階で3倍程度遅いか。ダイレクトスレッドコードとか、インストラクションのマージとかまだやれそうなことが山ほどあるので、とりあえずは気にしない。

先にバイトベクターを実装しようか、コアにかかわる部分をこなしてしまおうか。
ちと考えないと。

R6RSのシンボル

読み込みの部分でシンボルの解決をどうするか。

R6RSだと以下のシンボルは不正。
「.aa」「|a|」多分ほかにも。
こんな感じのシンボルがほしい場合は、string->symbolで作ってやる必要がある。しかし、ここで個人的には無視できない問題が起きる。
たとえば、ベクターを何らかの型のように使おうとしたとき、最初の要素は型の目印(タグ)にし、残りの要素をプロパティにするといった手法は良くとられるものだと思う。
例えばこんなコード。
(define (make-entity name desc) (vector (string->symbol ".entity") name desc))
(define (entity? e) 
  (and (vector? e) 
       (eq? (vector-ref e 0) (string->symbol ".entity"))))
これに、nameとdescのアクセサと識別用の関数を用意すれば簡易構造体である。

ここからが問題で、ではここでこのentityはシリアライズ可能だとしよう。schemeならwriteで書き出してやれば、entityは読み込み可能なS式として書き出される。こんな風に:
#(.entity name desc) ; mosh
#(\x2E;entity name desc) ; Ypsilon
#(|.entity| name desc) ; r5rs
でも、書き出されたこのタグはR6RSでは不正なシンボルなんだ。
せっかくオブジェクトをS式で簡単にシリアライズできるのに、こんなくだらない罠にはまりたくはない。writeで書き出すのはr5rs方式にして、readはYpsilon方式の「#!xxx」でスイッチできるようにした方がいいかもしれない。

そもそも、こんな使い方が間違ってる?

R6RSのライブラリ その5

まさか5つもこのメモが貼り付けられるとは・・・

ライブラリのバージョンに関する話。
R6RSのライブラリは識別子にバージョンリファレンスをつけることができる。そうこんな感じで。
(library (identifier (1)) ...)
バージョンは数字のリストである必要があり、import時には比較もできる。なかなかすごい機能だ。
import時に比較ができる、たとえばバージョン1以上とか、ということは、複数の同一識別子、別バージョンのライブラリを持つことも可能なのだろうか?
R6RSのSection 7.1に、
When more than one library is identified by a library reference, the choice of libraries is determined in some implementation-dependent manner.

訳:
もし、2つ以上のライブラリリファレンスが識別された場合、その(ライブラリの)選択は処理系依存によって決定される。
とある。
ということは、処理系が許せばライブラリをバージョン違いで複数定義することが可能なのだろうか?
調べてみた。
例によって使用した処理系は、Petite chez scheme(7.9.4), Ypsilon(0.9.6-update3), nmosh(0.2.6)。そのうちikarusとかも試してみたいがそれは後回し。

使用したプログラム:
(library (lib)
    (export test)
    (import (rnrs))
  (define test 'test))

(library (lib (1))
    (export test)
    (import (rnrs))
  (define test 'test-1))

(library (lib (2))
    (export test)
    (import (rnrs))
  (define test 'test-2))

(import (lib (1))(rnrs)) ;; (1)を取ったり、つけたり
(display test)(newline)
結果は見事自分の予想とは違っていて、petite, Ypsilonはライブラリの現在のバージョンと要求バージョンが違うといってエラー。nmoshはtest-2を返してきた、つまりバージョンリファレンス無視。

バージョンの違う同一ライブラリを同時に読み込むということが実際ありえるかというと、こんなテストでもない限りありえないとは思う。そういう意味では、nmosh(おそらくSRFI-72を拡張したexpanderを使用しているscheme処理系)は現実解としてバージョンを無視。petite、およびYpsilonは同時に読み込める同一名ライブラリを1つとし、リファレンスの比較を行うといったところか。
ちなみに、nmoshで(import (rnrs (5))なんてのを試したところ普通に動いたので、おそらく上記の推測はある程度的を射ていると思う。
(これが動くのをよしとするかは、また別の問題だとは思うが)
nmoshのバージョン無視はさすがにどうかと思うので、改修の少ないpetite、Ypsilon方式で読み込める同一名ライブラリは1つとしよう。これなら現在のLibraryクラスにバージョンを追加してやるだけで済む。

しかし、R6RSには微妙な言い回しが多い気がする。expand時の(for (rnrs) expand)とか。

2011-02-01

BoehmGCで気になること

BoehmGCを使っていていろいろ気になることが起きてきた。
正直起きてほしくはない、が現実を受け入れる。使い方が悪いのか?

現象としては、おそらく回収されてはいけないメモリが回収されてるっぽい。保守的なGCにもかかわらず!!
正確には静的に置いてあるハッシュテーブルの中身がある回数参照されたあと変な値になるというもの。
詳しく調べてないし、GDBで確認するのと普通の流すので結果が変わるので調べ難い(ひどい話である)ので、断言はできないが。
DLL内でGC_INIT()を呼んで、exeメインのファイルでもGC_INIT()を呼んでいるが、これがまずいのか、それともCygwinでは静的に置いた値に対して特別な処置がいるのか、どっちかは分からない。
涙が出そうになったのでデバッグを適当に切り上げてしまった。続きはまた明日。

どうでもいい話だが、どうやってポインタが指すポインタを判別してるんだろう?
例えば
typedef struct a
{
  int tag;
  void *addr;
} A;

int main()
{
  A *ap = GC_MALLOC(sizeof(A)); /* (1) */
  char *strp = GC_MALLOC(10);
  ap->tag = 1;
  ap->addr = strp; /* (2) */
  return 0;
}
プログラムに意味は無いが、こんなのがあった場合、(1)はいいだろう、スタックから辿れる。(2)はもしapがどこかで作られたものなら、strpのスタック上のアドレスは完全に消える。この場合、struct Aの中身を1byteもしくはalignのサイズ(例えば2byte)ずつ見ていき、GCが抱えるヒープ上のアドレスを保持しているかどうかというのを見るのだろうか?
こんな感じ?
void follow(void *obj, size_t size)
{
  uintptr_t addr = (uintptr_t)obj;
  int i;
  for (i = 0; i < size; i++) {
    void *p = (void*)(addr + i);
    /* p が指すアドレスの先がヒープを指しているか? */
    if (in_heap(*p)) {
      /* ヒープは割り付けたメモリのサイズを管理する */
      follow((void*)*p, get_size_from_heap_header(*p));
    }
  }
}
これなら一応アドレスを辿れそうに見える、試してないけど。

仮に、BoehmGCがこんな感じのことをしてたとして、誤回収が起きるのはどうしてだろう?もしくは、メモリを中身を書き換えてるのかも?
ソース読めば早いのだろうが、あれを読んで理解するのはかなり大変だよなぁ・・・そこまで時間をかけたくないし、なんかいい解決方法ないだろうか?

2011-01-30

エレヴェン

まずはこの動画を見てほしい。


いや、最先端だね。音声認識エレベーターとは。
でもスコティッシュアクセントには対応していなかったようだ。

これを同僚に見せられたときは思わず大爆笑してしまった。
うちの会社のCEOとマネージャーの一人はスコットランド人だけどね!!

2011-01-15

LinuxをUSBからインストール

をするための準備の話。
ちょっと古めのデスクトップが転がってて、OSが入ってない。Windowsはもちろんない。ということで、Linuxを入れようと思ったのだが、現在使ってるノートPCにはCDROMがない。

っでちょっと調べてみたらUSBからインストールできるらしい。ということでブータブルUSBを作成する。
手順。
  1. syslinuxを落としてくる。
  2. DAEMON Tool Liteを落としてインストール。
  3. Linuxのisoイメージを落とす。
  4. 3.を2.のツールでマウントして、中身をUSBドライブにコピー。
  5. USBドライブにisolinuxってフォルダがあるので、それをsyslinuxに変更。
  6. 5.のフォルダの中にisolinux.cfgというファイルがあるので、syslinux.cfgに変更
  7. syslinux.exeを叩く。(syslinux.zipで落としたなら、中のwin32フォルダにある)
    C:\> syslinux.exe -maf F:
    (F: はUSBドライブ名。これをC:とか自分のHDDにすると多分えらいことになる)
    本当は-maでいいんだと思うけど、僕のUSBはリムーバブルと認識されてなくて、強制書き換えの-fが必要だった。
たった(結構あるな)これだけ。

他にも、UNetbootinってツールも試したけど、こいつにはひどい目に合わされた。バージョンが悪いのか(最新版だけど)、そもそもCDイメージをUSBにコピーするだけのツールなのか知らないけど、ブータブルなUSBならない。

これで上手くいったらSSDを買って自分のノートにLinuxを入れよう。
(その前に死んだバッテリーを換えないと。ACアダプタ抜いたら即死ぬノートPCってノートの魅力0なんですけど)