Syntax highlighter

2011-04-28

letrec-syntaxにはまる

現在Racketのr6rs test suiteをパスしようとしているのだが、
(実は既に絶対にパスしないテストがあったり、テストライブラリをいじらないとだめだったりとかなので、すでのR6RSとは名のれないというのは確定なのだが)、
こんな初歩的なテストに引っかかってる。
(letrec-syntax ((my-or (syntax-rules ()
                         ((my-or) #f)
                         ((my-or e) e)
                         ((my-or e1 e2 ...)
                          (let ((temp e1))
                            (if temp
                                temp
                                (my-or e2 ...)))))))
  ;; 展開後ifが関数呼び出しに、マクロ内のtempが
  ;; すべてletで束縛しているものになる
  (let ((x #f)
        (y 7)
        (temp 8)
        (let odd?)
        (if even?))
    (my-or x
           (let temp)
           (if y)
           y)))
何がだめかというとsyntax-rulesの健全性がletrec-syntax内では崩れているということ。
逆に言えば、letrec-syntaxであればsyntax-rulesを使って伝統的マクロみたいなことができる、のだがまぁそれではだめなわけで。

理由は実は分かっている。
syntax-rulesはexplicit renamingで実装しているのだが、そのrenameが問題になっている。どういうことかというと、renameにはコンパイル時環境を使用してシンボルを識別子に変換しているのだが、その環境が問題になっている。letで束縛した束縛変数の情報がコンパイル時環境の中に含まれているため、マクロ展開時にシンボルの探索を行うと束縛変数が引っかかってくるのである。
っで、renameでは渡された引数がシンボルだった場合、現時点での環境を使用して識別子を生成するためおかしなことになるのである。

じゃあ、どう解決するか。
あんまりいい案がないのだが、syntax-rulesはパターン変数以外は外部と干渉しないことが分かっているので、パターンの中にあるパターン変数以外のシンボルをあらかじめ環境の中に入れてしまえばとりあえず回避できそうな気がする。
問題は、マクロ変換器がコンパイル時環境を直接触れないことか。
さてどうしたものか。

2011-04-20

自由パターン変数

とでも呼べばいいのか?
とりあえず、そのようなものに苦しんでいる。

syntax-caseの実装をライブラリではなく、builtinな実装に切り替えた。(可能ならライブラリにしたいが、今のところ不可能そうなので)
っで、(何度となくぶつかったが)ぶつかった壁がこれ。
こんなコードが怒られる。
(syntax-case
  (list (f (syntax c2) (syntax (c3 ...))))
  ()
  ((rest)
   (let ()
     (syntax-case
       c1
       (=>)
       ((e0)
        (print (syntax rest))
        (syntax (let ((t e0)) (if t t rest))))
       ((e0 => e1)
        (syntax (let ((t e0)) (if t (e1 t) rest))))
       ((e0 e1 e2 ...)
        (print (syntax rest))
        (syntax (if e0 (begin e1 e2 ...) rest)))))))
これはR6RSの何章かにあったcondのsyntax-case版実装を走らせて、途中経過をダンプしたもの。
何がまずいかというと、restが外側のsyntax-caseでパターン変数として現れているのだが、現状の実装では内側のsyntax-caseから外側のsyntax-caseのパターン変数は見えない。

現状の実装としては、
syntax-caseが現れたら、それのパターンとそのパターンの情報、出力部分とフェンダーをクロージャー化したものをmatch-syntax-caseという関数に渡して返している。っで、それがもう一回S式→内部表現の関数に渡されるという感じ。
自分でもここまではすっきりかけたなぁと自画自賛していたのだが(まぁ、Ypsilonの実装からかなり盗んだからだが・・・)、この自由パターン変数が現れてちょっと(だいぶ)躓いている。
上記にも書いたが、パターンのメタ情報はmatch-syntax-caseに渡しているため、どこかから取り出すということができない。この際、Ypsilonでは.varsというトップレベルの変数に入れて、実際に置き換えを行う際にテンプレートの変数が自由パターン変数かどうかをチェックしている。ように見える。
現状、そのような変数を導入してないので、どうしたものかということになるのだが、どうしたものか。

2011-04-15

今更ながらにR6RSのライブラリについて

R6RSのライブラリについて大きな勘違いをしていたかもしれないということに気づいた。

現状Sagittariusにおけるライブラリの扱いはfirst class objectになっているのだが、これが元でsyntax-caseの実装が難航している感がある。
どういうことか?
僕がR6RSのライブラリを正しく理解しているかは分からないが、このライブラリシステム、Javaのクラスとかパッケージの感じではなくて、それ自体がマクロの一部として扱われた方がマクロを実装する際に煩雑さが消える気がしている。

実はこうではないかと思っている案
(library (something)
    (export do-something)
    (import (rnrs (6)))
  (define (print . args)
     (for-each (lambda (arg)
                  (display arg))
               args)
     (newline))
  (define (do-something . args)
     (print args)))

(import (something))
(do-something 1 2 3)
ライブラリがマクロであると考えると、これはこんな感じで展開されるはず
;; #: プレフィックスはrenameの結果とする
;; このプレフィックスはユーザが指定できないようR6RSでレキシカルエラーになるものがよい
;; print -> #:print
(define (#:print . args)
  ...) ;; 中身は一緒
;; do-somethingはexportされているのと、
;; 呼び出し元でprefixもしくはrenameで変更されていないのでこのまま。
(define (do-something . args)
  ...) ;; 中身は一緒
;; メインのプログラム
(do-something 1 2 3)
こう考えれば、ライブラリは展開時(読み込みとはもはや呼べないので敢えてこう言う)にrenameできるので、名前の衝突はなくなるし、C/C++のincludeより多少高等ではあるが、最終的に実行単位は1ファイルということになる。
また、R6RSでは定義の書き換えが禁止されているので(あんまりこれに追従してる処理系は多くないけど)importされた定義が書き換えられるということはない。

と、こう考えると、なぜimportレベルが与えられたのか分かる気がする。つまり、ライブラリを展開する際に先にimportしておかなければならないライブラリがどうしても必要になるからだ。たとえばsyntax-case内で使用される手続き。
これらの手続きは展開時に実行される必要があるので、import時にコンパイラもしくは実行する何かに教えてやる必要がある。曰く、この手続きはマクロ展開時に*実行*してね、と。単純に考えれば、マクロ展開器はevalを使う必要が出てくるということになる。
そもそも、importレベルはsyntax-caseのために導入されたのじゃないかと思うが。個人的にはcondition systemと一緒で言語仕様から切っても切れないものをライブラリと呼んではいけない気がする。evalは一応ライブラリか。しかし、Primitiveでないと実装できないようなものをライブラリと呼んでいいものか。
(error、とかassertion-violationなんてもろCondition Systemに依存してるくせに言語仕様の方に入ってるしなぁ。どうよ?)

さて、この考え方が正しいかどうかは別として(いろんなR6RSの処理系(といってもmosh、Ypsilon、petiteの3つだが)を見てると正しそうではあるが)、この方法で実装するとなると、現状のSagittariusを大幅に変える必要がでてくる。
そもそもライブラリなんていらんかったんだってことになるからだ。
ここまで作ってやり直しになるとさすがに凹むので、別の解を見つけたいところではあるが、いい案が思い浮かばない。

2011-04-14

段々

無理ゲーになってきた感がある。> syntax-caseの実装

とりあえず考えをまとめる。
まずは現状の問題点。

  • 展開結果にer-macro-transformarが使えない。
    • renamingに環境が必要だが、syntax-caseがネストした場合どうする?
  • 地味にsyntaxの方が問題になる
    • syntaxが実際のtemplateを書き出すのだが、別にした場合に上記のrenamingの問題が発生する
  • (syntax-case (list e0 ...) ...)というsyntax-case
    • マッチ対象が展開されている必要がある。
      • 展開をどうする?
    • マッチ対象のコンパイル時環境をどうするか。
      • 一発で展開すると環境が捕捉できない
      • lazy(コンパイラに任せる)にするとどうなる?
  • その他、自分の力不足
    • 正直これが一番大きい・・・
まぁ、まだいくつかありそうだがとりあえずこれくらいで。
4つ目はいかんともしがたいとして、どうしようかね。

現状挑戦したのが展開時に中に含まれるマクロを全部展開しようとしたのだが、上手くいかなかった。
問題はsyntaxで、templateの展開が上手くいかない。
単純なのはいいのだけど、with-syntaxを使ったのとか、別のマクロがネストしててそのなかで構文オブジェクトを返そうとすると上手くいかない。
(単に展開のやり方がまずいのだろうけど、ごちゃごちゃしてきて理解の範疇を超えた・・・)

煩雑になるのは望むところではないのと、ライブラリがコンパイラのついて知っていないといけないというのは気持ち悪いので、syntax-case展開時にマクロを検知、展開するのはやめる方向にしよう。

問題はsyntaxが持つtemplateをどうするかだ。
後にしよう・・・

syntax-case再び

RacketのR6RS Test Suiteを導入しようと思ったらテストを実行するのにレコードが必要で、レコードはdefine-record-typeなんてので定義されてて、その定義にはsyntax-caseが必要っぽいので再びチャレンジすることにした。
(長い一文だ)

とりあえず気づいたことというか、これはひどいなぁと思ったことについて。
R6RSの仕様書的にはsyntax-caseはライブラリであると明記されているのに、コンパイラにマクロ展開のタイミングを強制すること。たとえばこんなコード。
(define-syntax test
  (lambda (x)
    (define (hoge x) (syntax-case x () ...))  ;; (2)
    (syntax-case x () ;; (1)
      ((_ x)
       (hoge #'x)))))
これで何がおきてほしいかというと、(1)のsyntax-caseはxがパターンマッチにマッチしたら、(2)のdefineを呼ぶ必要がある。でhogeが構文オブジェクトを返して、コンパイラはその構文オブジェクトをコンパイルする。
でも、hogeを呼び出すためにはコンパイラがすでに内部defineをコンパイルしている必要がある。

あぁ、でももう少し考えればいけそうな気がしてきたなぁ。
問題は現状では構文オブジェクトを返してもコンパイラはそいつをコンパイルしてくれないことか。

ちょっと気づいたことメモ。
(syntax x)とした際に、環境を捕捉する必要がありそうだ。
結局上の式は、
(define-syntax test
  (lambda (x)
    (define (hoge x) (let ((expr x)) ...)) ;; something
    (let ((expr x))
      (if (match? x)
          (hoge (syntax x))))))
こんな感じに展開されればいいのか。(まぁ、実際にはhogeはletrecな何かだろうけど)

2011-04-12

custom port実装中

とりあえずいろいろ見ながら実装しているのだが、custom-textual-output-portの実装の違いというか、いいのかこれ?っていうのを発見。
たとえばこんなコード
(import (rnrs)
 (rnrs mutable-strings (6)))
(define (print . args)
  (for-each (lambda (arg)
       (display arg))
     args)
  (newline))

(define (custom-read! bv start count)
  (string-set! bv 0 #\a)
  1)

(define (custom-write! bv start count)
  (print bv)
  1)

(define cp (make-custom-textual-output-port "id" custom-write! #f #f #f))
(print (put-string cp "string"))
(close-port cp)
これをmosh, Ypsilon, Petite Chez Schemeに食わせてみる
mosh:
s
t
r
i
n
g
#

Ypsilon:
string
tring
ring
ing
ng
g
#

Petite Chez Scheme:
#
string

string

string

string

string

string

ちなみにPetiteは最後のclose-portがないと「string」が出力されない。ちなみに、write!のプロシージャーに渡されたstart、countもそれぞれバラバラで、moshは固定値「0,1」、Ypsilonはstartが0固定で後はsubstringしたかのような長さ、Petiteはstartとcountの合計値が文字列の長さになるようになってた。
(日本語が下手なので、詳しくは動かしてください)
これinput-portで作ってもそれぞれ実装がバラバラで、正直なんだこれ?状態。

いまいち使いどころが分からないし、とりあえず簡単そうな実装にしてしまおう。

2011-04-07

Google Chrome

For some reason, my firefox 3 and 4 didn't work well. I got horrible internet connection with it, such as google.com could be seen but not hatena.co.jp. First I thought it was because of my laptop, so I actually disassembled it and cleaned it. But unfortunately it wasn't it. Then I installed IE8 which I really didn't want to, and I really wish that was it. Well, as you can see it wasn't it, *AGAIN*.

I didn't have any idea what was wrong, I've even uninstalled my AVG which is a free virus software because I thought it has own firewall, however it didn't change any thing. Actually, I got less memory consuming as a result. But I'm kind of chicken so I've already installed new anti virus software, AVAST!. It's light and less memory than AVG so far I like it.

When I installed it, it recommended to install Google Chrome. Frankly, I've been avoiding to install it, because I felt like Google steal my private information such as the history of my browsing. I don't want them to know my porn site history XD. Just joking.

So far, it's pretty good. It's fast as they say and its style is really simple. One thing I have a problem with this. It can't import my bookmark from firefox. I think this is because my firefox's profile is broken. Does any body know how to fix it?

2011-04-01

4月1日

世間ではエイプリルフールだが、僕にとってはちょっと違う意味を持つ日。
某マイミクは同じ意味の日を「独立記念日」と名づけているが、僕はもともと独立していたのと特に名前をつける気がないので名はない。
あまり引っ張ってもしょうがないので、この日は僕がオランダに来た日。2009年4月1日に来たので今日で丸2年。
特に感慨深いということもないが、時が立つのは早いものだ。

最初の1年はいろいろわからないこともあり、不安な日々もあったと思うが、2年目はこなれたものであった。未だにオランダ語はうまく話せないし、生活は不安定ではあるが、許容範囲だろう。
こっちに来て得たものは大きい。特に昔持っていた価値観が大きく変わった気がする。主に仕事に対する考え方というやつだ。
日本にいたときは、もちろんそれが日本式なのはわかっているが、「会社が何かをしてくれるのではなく、自分が会社のために何ができるか」ということをが正義(ちょっと違うか)だった気がする。個人個人がまるで経営者にでもなったかのような考え方だと思う。仕事を通じて人間形成をするとか、会社の利益のために何ができるかとかそんなことだ。
それ自体は別に悪くないと思うし、日本という国はそうやって今の地位を気づいた部分もあると思う。でも、そこに僕(自分)はいないんだよね。
その考えがこっちに来て大きく変わった。もともとその考えに対して大きな違和感を持っていて、それが元で転職したり、カナダにワーホリにいったりしたのだが、その違和感がここに来てはっきり分かったというべきか。
こっちの人たちは、ある意味当たり前だが、日本式の考えでは働いていない。まず、自分があって会社は、その人のキャリア形成にもよるが、生活の糧を得る手段といったものだ。だから、より良い条件を提示する会社があればすぐにそちらに移る。勤続年数なんてものに意味はなく、自分が何をしたか何ができるかということにだけ意味がある。なので、会社への忠誠心とかは薄く、そもそもそんなものないと思うが、自分の生活もしくは家族が第一である。
よくあるドラマの台詞(よくあるのか?)で「仕事と私どっちが大事なの?」なんてのがあるが、この国ではそんな台詞吐くまでもなく答えは明白である。

日々の生活に特に不満はない。むしろ、もう日本に戻れないだろうという気さえしている。堕落したのかこれがあるべき姿なのかは分からないが、あまり気負って仕事しなくていいというのは心にゆとりができる。もしかしたらできすぎたのかもしれないが。
3年目は何を得るのか分からないが、楽しい1年になるという気はしている。

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月にチケットとってたら張った押したくなるくらいの仕打ちだわ)