Let's start Scheme

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