Syntax highlighter

2011-07-10

ドキュメントを書き始めた

いろいろ何を使おうか悩んでいたが、別にtexinfoとか自前で何か作るとかは馬鹿らしいなぁと思ったので、結局OpenOffice.orgのWriterにした。
それでいいのか?という疑問は未だに付きまとうけど、単なるAPIドキュメントという側面だけではないようにしたいと思うと割としっかりしたドキュメント作成用のソフトが要るようになる。わざわざテキストファイルで書いてくTexとかはあまりに面倒だし、今から覚えるのも億劫だったという理由から。
最終的にはOOoフォーマットからLaTexか何かに変換してHTMLを出力という形に持っていこうとは思っている。OOoフォーマットだとソフト持ってないと読めないし。

ドキュメントと書いてて思ったのが、かなりの分量が必要になるということ。R6RSで規定されている関数とかも全部書いているからなのだが、かなり凹みそうになる。なぜそんな部分まで必要になるかというと、R6RSで規定されている関数を拡張しているものがあって、単純に仕様書にポインタを指すということができないから。
割とコピペで済ませる部分が多いが、これをやってて仕様を満たしていない部分を発見したりするから割と有用かな(今まで必要な部分しか読んでなかったというのもあるが)。時間かかるけど。

2011-07-09

とりあえず一旦完了

Compiled Cacheの実装が一旦完了した。キャッシュから読み込むと3倍くらい早いのでまずまずだろう。
いくつか問題点があって、
・依存関係にあるキャッシュが変更された際に上手く動かない
・キャッシュ自体が壊れていた場合に上手いことエラーハンドリングしない
などというところがとりあえず分かっている。
が、問題だなぁと感じてから直すことにする。

ほしいと思って投稿してからほぼ1週間これの実装にかかったわけだ。結構かかったな。
まぁでも、それなりに待てる時間まで実行時間が短縮されたので無駄ではなかっただろう。

2011-07-07

はまってたこと

ずいぶん長い間気づかなかったが、Cygwinのマウント形式に長いことはまっていた。
Cygwinはバージョン1.7からfstabが使えるのだが、それを最初に記述した際に、NTFSをtextでマウントしていたみたい。
っで、賢いのかバカなのか分からないけど、Cygwin上でread(freadではない)を行った際に、\r\nが\nに自動的に変換されていた。
バイナリで扱ってほしいのに、そんなものまでテキストにされていたとは。

Twitterでつぶやいた1バイトスキップされる問題はこれだったということ。こんなの中々気づけないよ。

2011-06-30

思案中のこと

Sagittariusが遅い。
結構まともなライブラリを作ろうとしているのだが、それのテストというか1回走らせるのに2~3秒、長いときで5秒以上待たされる。ライブラリを除いた実際のコードは数行なのにだ。
これは、まぁ、原因まで全部分かっていて、コアの機能以外は全部そのときに読み込んで、コンパイル、実行しているからだ。さらに、マクロ展開の関係もあって、コンパイラがかなり重い。

っで、FASLを導入してみようかと思ったのだが、これって単にS式をバイナリにしただけなのね。それでは結局上記のルーチンが走るので美味しくない。どうやら本当に必要なのはCompiled Cacheのようだ。

名前などどうでもよくて、それが要ると思って考えていたのだが、いろいろ解決しなければならない問題が既にある。

・ライブラリ単位にするか、ファイル単位にするか。

どちらも問題があるが、ライブラリ単位がすっきりしてると思うのでそっちで。

・複数ライブラリが1ファイルにある場合はどうするか?
・ライブラリ外でモジュールを読み込んでからライブラリを作成しているファイル(実際既にある)ものはどうするか?
・どの段階でキャッシュするか?
・実行ファイル内(この場合は起動ファイルを指す)で、ライブラリを定義した場合にそれをキャッシュするか?

思いついたというか、考えている段階で答えが浮かばなかったのがこの辺。
4つ目は最悪キャッシュしてしまえばいいか。っで、import時に引っ掛けると。ただ、キャッシュ時間が問題になりそうだ。

さて、どうしようかな。

日本人がオランダに長くいすぎてしまったと感じるとき

これの逆版
あんまり思いつくこともないんだけど、面白そうだから。

1.電車やバスが10分以上遅れてもなんとも思わない。
日常的に10分くらい遅れる。というか時刻表はたんなる目安でしかない。

2.自転車が歩道を走ってると警察を呼びたくなる。
自転車用の道があるんです。

3.シリコン製のへらを日常的につかう。
けちなオランダ人は、洗う必要がなくらいきれいにビンの中身を食べます。

4.大麻のにおいが嗅ぎ分けれるようになった。
一応、コーヒーショップの外では吸ってはいけないはずなんだけど。

5.休暇が1週間だと短いと感じるようになった。
まとめて取れるんです。

6.残業する人を見ると可哀想だなぁと思うようになった。
まぁ、滅多に見ないけど。

7.自分は背が低い方だと思うようになった。
成人男性の平均身長185cmだったかな?

ネタが尽きた。
7個とは微妙すぎる数字だ。
なんかあったらまた書こう。

単に行き詰っていたので息抜きに書いてみたとも言う。

2011-06-28

発見し難いバグ

原因を特定しにくいと言うべきか。
まぁそんなバグに悩まされている。Javaや元々GCがあるような言語なら問題ないのだが、(ここまで言ったら何の問題かすぐ分かるが)、メモリー管理の問題である。

現状SagittariusではBoehmGCを使っている(そのうち取り替えてやる!と思っているが、GCはむずい。。。)。別にGCが悪いというわけではなく、どこかでメモリー破壊が行われている可能性があるとう問題。
読み込んだシンボルが、ある特定のプロセスを踏むと変更されている。発現性は100%なのだが、場所の特定ができない。この前、正規表現を実装している時に同じ現象が起きた。そのときは割り当てたメモリを越えて値を埋めていたので起きたのだが、その際の原因は非常に簡単で、メモリのサイズの計算が行われていなかったというもの。
例えば、mallocでintの配列10個確保するのにこう書いてたという問題:(int)malloc(10)
JavaやC++やってるとnew演算子が便利すぎて忘れる問題の一つだと信じている。信じたいとも言う。っが、今回はどうも違うらしい。メモリ割り当ての箇所を全部チェックしたが問題ない。ということは、割り当て時の不具合ではなく、使用時の不具合なので、それが使用されている箇所を全部洗いなおす必要がある。正直、砂漠の砂を数える気分になる(そんなにはないが)

どこかにいいメモリ破壊検出ツールはないだろうか?

2011-06-26

(match)ライブラリで見つかった気になるバグ

Sagittarius Schemeは一応Andrew Wrightのパターンマッチが使えるのだが、それを使用したプログラムで起きた気になるバグの話。

現在Sagittarius SchemeではCとSchemeを繋ぐ仕組みとして.stubファイルを使用している。ちなみに、アイデアはGaucheからいただきました。っで、そのファイルをcgenというSchemeで書かれたプログラムに処理させてCのファイルを生成する。利点はわずらわしい引数の数のチェックとか、型チェックとかをそれなりに省略できることと、Schemeのマクロチックにマクロを記述でき、かつそれらが確実にインライン展開されること。実際、.stubファイルから生成された.cファイルはサイズが4倍程度に膨らむ。つまり記述量が4分の1ですむということ。
話がそれた。そのプログラムでは上記のmatchを使っているのだが、最近変更したsyntax-rulesをsyntax-caseで実装するというので問題が起きた。matchの中で'_が単なるシンボルとして比較されていたのだが、syntax-rulesで生成された後のS式は全部ラップされて識別子になっている。っで、'_の比較が失敗するというもの。
何が気になるかというと、これからもしmatch相当の何かを書くことがあった場合、この辺を気にしないといけないということと、他のR6RSの実装ならその辺を気にしなくてもいいということ。正直、他の処理系との移植性は大分あきらめた部分はあるのでどうでもいいのだが、'_とか'...が識別子にラップされてもいいのかなぁとちょっと不安になってたりする。
現状動いているものを変更するのは怖いので(単に面倒くさがり)、とりあえず現状のまま様子をみて、問題が発生したら変えるということにしよう。

P.S.
Twitterをはじめました。アカウント名は@tk_ripleです。こういうところでさらしていいものなのかもわからないのですが、どうせ見てる人も少ないということで。

P.S.2
最初に登録したユーザー名から上記に変更してます。こんなものも変更できるのね、Twitter。

2011-06-25

めがね

前の眼鏡を5年以上使っていたので、新しいのを買った。
Tommy Hilfigerというブランド物である。まさか自分がブランドの着いたものを買うとは夢にも思わなかった。

つけた自分を鏡で見たときに、なんともトレンドな感じがして違和感を覚えたが、まぁいいか。

以下は余談。
こっちでは視力の指標に+-数字というのを使う。
例えば僕の視力は-6(左)と-8(右)という結果だった(ちなみに、マイナスは近視でプラスは遠視)。今まで日本の0.1とかと違って自分がどれくらい目が悪いのか分かり難い。
慣れの問題ではあるのだが、単位が変わるというのはいつでもそれに対応するのに困る。

2011-06-18

ぐぬぬ

syntax-rulesが遅いのでsyntax-caseで実装したものを試してみたら、動かない。いや、動くんだけど、正しく動かない。
その理由も分かったのだが、解決できる気がしない・・・

理由は分かれば単純なのだが、例えばこんなの。
;; testはR6RSテストスイートのマクロ
(test (let ((x 'outer))
   (let-syntax ((m (syntax-rules () ((m) x))))
     (let ((x 'inner))
       (m))))
 'outer)
これは割りと典型的な例で、マクロの中でマクロを生成すると起きる。(実は違うかもしれない)
この例だと(m)が返す値はouterじゃないとまずいのだけど、innerの方を返す。何故か?
syntax-caseがパターンとテンプレートをコンパイルする際にすべてのシンボルを識別子へと変換する。その際に、すべてのxが同一の識別子に変換されるので、let-syntax内にあるxとinnerそ束縛しているxが同一のものになってしまう。
これを回避するうまい方法が思いつかない。マクロの展開フェーズとコンパイルのフェーズが分かれていれば、マクロを展開する際に使用する環境やらマクロ展開フェーズやらがいろいろ知っていればいいのだが、現状の実装ではletが変数を束縛するということを知っているのはletに束縛された構文オブジェクトだけなんだよね。
また、マクロを展開してからコンパイルするわけではないので、マクロ展開中に変数束縛を作るマクロが出現した際に結局おかしくなる。
こうなってくると僕の足りない脳みそでが悲鳴を上げてくる。
現在の実装はYpsilonのものをSagittariusでも動くように適当にいじったものだが、根本的な理解をしていなかったため結構穴がある(例えば上記のものとか)。
この穴をふさぐためには実装のしなおしだろうか?しかし、そもそも今のモデルで上記のような問題を解決できるのだろうか?

・・・

考えるか・・・

2011-06-16

Socketが動いた!!

Socketの実装が完了。まだテストケース書いてないけど・・・

とりあえず簡単なechoサーバーを書いてみた。
(import (sagittarius socket))

;; creates echo server socket with port number 5000
(define echo-server-socket (make-server-socket "5000"))

;; addr is client socket
(let loop ((addr (socket-accept echo-server-socket)))
  (call-with-socket
   addr
   (lambda (sock)
     ;; socket-port creates binary input/output port
     ;; make it transcoded port for convenience.
     (let ((p (transcoded-port (socket-port sock)
          ;; on Sagittarius Scheme native-transcoder
          ;; uses utf8 codec for ASCII compatibility.
          ;; For socket programming it might be better
          ;; to specify eol-style with crlf.
          ;; But this sample just shows how it goes.
          (native-transcoder))))
       (call-with-port
 p
 (lambda (p)
   (put-string p "please type something\n\r")
   (put-string p "> ")
   ;; gets line from client.
   (let lp2 ((r (get-line p)))
     (unless (eof-object? r)
       (print "received: " r)
       ;; just returns message from client.
       ;; NB: If client type nothing, it'll throw assertion-violation.
       (put-string p r)
       (put-string p "\r\n> ")
       ;; waits for next input.
       (lp2 (get-line p)))))))))
  ;; echo server waits next connection.
  (loop (socket-accept echo-server-socket)))
これを起動しておいて、別ターミナルからtelnet localhost 5000で繋ぐと動く動く!!
あんまりにうれしいので、example/socket/echo.scmとか作ってしまった。初example!!

次はFFIでその次がGUIか。
GUIまでできたら実用的なアプリを書きたいなぁ。

2011-06-14

宗教観

<<警告>>
以下の文章は繊細な問題をダイナミックに否定しています。中東辺り発祥の宗教に属している方は読まないことをお勧めします。もし気分を害したり、聖戦だぁ!なんて言い出されても当方は一切責任を取りません。

身近な人がユダヤ教に改宗しようとしているのの関係で、元々宗教、特に中東辺りを発祥とするものが嫌いだったのに拍車がかかった。
とりあえず、前々から思っていたこととして、唯一神教は総じて腐っているということ。
何故か?こいつらの過激派は自分たちの神のためといって戦争を起こす。また、他宗教の人間を邪教徒といい虐殺する権利を持っていると言い放つ。実際、現在問題になっているテロリストの多くはイスラム教だし、歴史を紐解けばキリスト教が起こした略奪戦争は多々ある。
また、神父、宣教師、その他いろいろは神の言葉と称して人の洗脳を行う。その昔日本でも宣教師が神の教えと称し、奴隷として人々の売り買いをしたことは割と有名だと思う。そのため秀吉はキリスト教を全面的に禁止したとかしないとか(多分理由の一つだろう)

正直中身の教えに関してはどうでもいいのだが、とりあえずユダヤ教についていろいろ知ってしまった。まぁ、そのために嫌いになったという話もあるのだが。
とりあえず、ユダヤ教の好きになれない食べ物の話。
彼らにはKosher(日本語訳は知らない)というルールがあって、割と厳しく食べていいものとだめなもの、混ぜて食べてはいけないものがある。中でも一番気に入らないのは、Kosherな肉というやつだ。
正直何が普通の肉と違うのかはさっぱり分からないが、彼らの話によると、宗教上他の生き物の苦しみを体内に取り込んではいけないため、できる限り苦しまないよう殺した肉のみを食べるという。この段階で傲慢さがにじみ出てるなぁと個人的には思うのだが、まだまだある。豚は不浄な生き物なので食べない。魚はいいけど、海老とかは海の昆虫なので食べない。Unkosherなものを作った鍋は使ってはだめ、だってその鍋には苦しみが染み付いてるじゃん。
ちなみに、彼らによるとKosherでない肉はBAD MEAT(訳は適当に自分でどうぞ)なんだそうだ。つまり、我々が食べている肉は中に苦しみが詰まっていて、食べるには不浄な物なんだと。(そこまでは言ってないかも--;)
個人的にKosherとか単なる言い訳にしか聞こえなくて、「肉食べたいけど、教えに背くなぁ・・・よしそれっぽい規定作って食べれるようにしよう」という風にしか見えない。素直に菜食主義になれと言ってやりたい。(というかもう言ったが)

つらつら書き出すと止まらなくなりそうなのでこの辺で。
でも、何よりも一番怖いなぁと思ったのは、宗教は人を変えるということ。大抵の場合は悪い方に。人と話す際の3大タブーに、政治、人種、宗教があるが、まさにそうだなと実感した。彼らは自分たちの宗教に関する否定的な意見は聞きたくない。まぁ、そこまでは分かるが、問題だなぁと思ったのは、こちらが疑問に感じたことを質問しても攻撃的な態度だと多くの場合は捕らえる。何故か?理由はおそらくいたって簡単で、「自分が何の疑問も無く信じていることに対して疑問を投げかけるなど、その宗教があたかも信仰するに値しないごみくずのように扱われているかの様に感じる」のだろう。そこにもはや言論の自由はない。
っが、困ったことに宗教人というのは多かれ少なかれ自分の信仰しているものを他人と共有したがる傾向がある。そうすると事は複雑になって、相手はこちらからは肯定的な意見しか聞きたくないが、こっちはそんなもの聞きたくないので否定的もしくは懐疑的な反応しかでない。こちらが大人の対応を見せて聞き流す、もしくは肯定的に適当な相槌を打つということをすればいいのだが、そうした際にこちらにもその宗教に対して興味があるなんて思われたくないし、肯定的な理解をしているとさえも思われたくない。この辺は個人的に譲れない部分になるので、関係が悪化しようが、瓦解しようがおそらく反応は変わらない。

これを読んで、本当にそんなことあるのかよ!と思った方、多少の脚色はあるけど上記の意見は体験に基づくものだったいりするのです。
もし周りに、なんらかの宗教に改宗しようなんて考えている知人がいる方、その人と良好な関係を保ちたいなら全力で止めることをお勧めします。

2011-06-12

マルチスレッド

とりあえずなんとなく形になってきた。
Windowsでも動くようにしたら後はバグ取りなんだろうけど、どこにバグがあるのかさっぱり分からない。マルチスレッドは難しいなぁ。正直、デッドロックが発生した際にそれがC側なのかScheme側なのか判別が難しい。今になって必要だったかなぁ?と少し疑問も。。。

それはさておき、現状で少し(大分?)問題が露呈してきた。
まず、遅い!!
通常の状態ならそこまで遅くないのだが、(rnrs)ライブラリのimportが遅い。理由は分かっていて、(rnrs)ライブラリをimportすると40近いファイルをロード&コンパイルする。これはそもそもr6rsのスタンダードライブラリが20以上に分かれていて、Sagittariusの実装ではそれぞれがファイルになっている。っで、さらにその中に実装の記述が入っていて、初回ロードでコンパイルと実行がなされるので遅い。
この辺、MoshとYpsilonでは(rnrs)ライブラリを組み込みにしていて、少なくともコンパイルの処理がカットされているのでそこまでの負荷にはなっていない。加えて、Sagittariusではsyntax-rulesが重たい処理なのでR6RSが要求するcase-lambdaなどsyntax-rulesで記述されているマクロのコンパイル及び、展開が非常に重い。これはsyntax-rulesをsyntax-caseで書けば早くなるのだが、何故かexportが上手くいっていないのでとりあえず保留にしてある。
次いで、エラー処理。
with-exception-handlerやguardマクロを使って何かを記述した際に、C側(VM含む)で何らかの例外を投げると、例外処理がされずに終了することがある。これも理由は分かっていて、Schemeで記述されたassertion-violationをC側で呼び出さないと落ちる。理由は分かっているのだが、最終的に同じ関数を呼び出すのになぜこれが起きるのかいまいち理解してない。とりあえず、VMと、CとSchemeを繋ぐ部分のエラー処理でassertion-violationを使用することで回避。
まだいくつかあるけど、大きなのでREPLがない。
REPLを実装すること自体はそんなに難しくないんだけど(履歴なし、変な入力を受け付けないものならSchemeで実装されたものがあったりする)、そのままでは使い辛すぎてもう少し何とかしないと、と思いつつ他の方にいってて進まない。どうしようかな。

落ちはない。

2011-06-02

iPhoneのiOSをバージョンアップ

してる最中。
やってる途中でいろいろ問題が発生して焦ったがなんとかなりそう。
写真とか残ってるといいなぁ・・・

とりあえず起きた問題。
  • iTunesのアップデートでCドライブの空き容量がなくなった。
    • .Net Frameworkをアンインストール
    • Open Officeをアンインストール
    • 復元ポイントの削除
    • WINDOWSフォルダ内の$NTinstallフォルダを削除
      • 600MB -> 2.3GBまで増えた
  • エラー番号1604が発生
    • Appleのサイトに詳しいトラブルシューティングがあったので実行
今のところ同期作業が進行中で何とかなったくさい。あとはJBするだけか。SBSettingsがないと不便すぎるのよw

2011-06-01

Verion 0.1.0

とりあえずそんなバージョンでリリース。
単にこれから加える変更は0.1.0以降と決めていただけで、当初の目的であるR6RS準拠というところまで実は行っていない。自分用のアプリが書ければいいや、という風に思っているのでそこまで気にしなくてもいいだろうというのもあるが。
なんかの格言に、「どうにも行かなくなったらそれをバージョン1と呼べ」なんてのがあったけど(コンピュータージョークだったかな?)、そんな感じ。

とりあえず、0.1.0から0.2.0の間でやりたいなぁと思っていることとその優先順位。
  1. マルチスレッド
  2. ソケット
  3. FFI
  4. GUI
そこそこ実用的なことを書こうと思ったらこれくらいはいりそう。1.はsrfi-21準拠にする予定。srfi-21はsrfi-18の後継みたいなので。でも、Larcenyとかsrfi-18, 21はPOSIXを前提にしてるからサポートしないという姿勢もとってるし、変えるかもしんない。
ソケットは、YpsilonとMoshのAPIが一緒だった気がするので、それに合わせる予定。何があるか列挙しないと。
FFIはYpsilonから盗む。正直自分の頭で考えられるようなものじゃないくせに、あると非常に便利なので。あと、dlopen相当のものが必要になってくるはずなので、その辺も考える。
GUIは設計から考えないといけないんだよね。JavaのSwingみたいにしようかと思ったけど、あれってオブジェクト指向じゃないと厳しい気がする。ActionListenerとか。Qtのシグナルみたいな感じにするといいかな?

優先順位は上から高→低なんだけどどれも全部ほしいので頑張る。ただ、ソケットとマルチスレッドは実装の順番を入れ替えるかもしれない。
まずは、こういった足すことを前提にしたCから使えるユーザーオブジェクトの作成からかな。Schemeからは実は近いのがあるんだけど(いろいろおかしなことになってきてるけど、ばっちり使われてる)、Cからそれを使うのは結構厳しい。なのでCから使われることを前提にしたものがいる。構想はあるのでとりあえずやってみる感じ。ただ、同時実装に近いものになるだろうので、第一号はソケットかスレッドのどちらかになる。難易度の低そうな方とも言う。

上記ができたら、DBIとかの実装もできるだろうか?
仕事で使うツールとして今の玩具の状態を早く脱したい。

2011-05-31

BBCニュースより

iPhoneでBBCニュースを読んでいたときに見つけた記事。
Japan pensioners volunteer to tackle nuclear crisis

(リンクが切れてても知りません)

僕のiPhoneにはBBCとNew York Timesのアプリがあるのだが、BBCの方が記事が短くていい感じなのでよく使ってる。
(あと、割と文章が平易なので読みやすいというのもあるが)
っで、今日上記の記事を見つけた。
訳を載せていいのか分からないので、要約だけ。
定年を迎えた元原発作業員の方が、同年代の同僚、友人に声をかけて自分たちが福島原発での作業を行うように働きかけている。論理的に60歳を越えたら放射能による癌が発現しにくいため(発現するまでに13~15年かかるので、それまでに寿命がくるという意味で)、若者よりもリスクが低い。だが、決して「神風特攻隊」ではなく、「生きて返ってくる」という意志の元で行う。
大体こんな感じ?(要約苦手な上に、日本語が出てこなくなってる・・・)

こういう方が戦後の日本を支えたのかなぁと思う一方、余生を満喫してほしいなぁとも思ったり。

2011-05-30

syntax-rulesの挙動がおかしい件

の原因が分かった。
分かってしまえば非常に単純かつ根が深い問題である。
原因は、quoteをした際に識別子がunwrapされてしまうため、環境の参照の際に見つからなくなるというもの。
なので、quoteが現れたときにunwrapしなければこの問題はおきない。

なんだけど、syntax-rulesないでquoteしたシンボルをwriteもしくはdisplayを使って出力した際に、S式ではなく識別子が出力されてしまう。
多分これを回避するためにunwrapしたんだと思うけど、それではまずいよなぁ。
どうしたものか。

2011-05-29

ドイツに行ってきた

この帽子ドイツんだ?オランダ!
ということでドイツに行ってきた。

といっても、ベルリンとか遠いところではなく、オランダとの国境から比較的ちかいところ。
その辺にMovie Parkなるものがあるといことで行ってきた。
どんなのかなぁと思っていってみたら、Universal Studioのドイツ版でした。サイズは日本のより少し小さいくらいか?でもローラーコースターもあったので、その気になれば比較的遊べると思う。
と思うと書いたのは、僕は無理だったので・・・いや、すべてのアトラクションがドイツ語だし。大学の時に第2外国語でとったけど、きれいさっぱり忘れたし。Ich bin ein Berliner Bal だけではねぇ・・・

そんなこんなであまり遊べず、帰りの電車の関係もありデュッセルドルフに移動。ここにはラーメン屋があるという噂を聞いたので食べれたらいいなぁ、くらいの感覚で来たのだが、これまたびっくり、一つのとおりが日本人街になってた!!
あと、なにかのイベントがあるのか、アニメキャラクターのコスプレイヤーが一杯。よくネットで海外のコスプレはレベルが高いというのを見るのだが、ありゃPhotoshopの技術が高いのか、1割くらいの当たりの写真を使ってるかのどちらかだと思う。
実際、9割くらいはGood looking boy/girlではなかったので(叶姉妹風。古い?)
目的のラーメン屋も意外とあっさり見つかり、辺りからは日本語の会話が山ほど聞こえるなか、ラーメンを注文。普通か旨い部類に入ると思うけど、あんまりラーメン通ではないのでよく分からん。
でも、醤油ラーメン、タンタン麺、餃子+飲み物2つで29.20ユーロは高くね?

//////
投稿を分けるのも面倒なので、こっちに。

ドイツに、というときはデュッセルドルフに行ったときに感じたこと。
海外で日本人に会うとどうも変な気分になる。理由はよく分からなかったんだけど、ラーメン食べてるときになんとなく分かった気がした。
彼らも英語(もしくはドイツ語)を話す。なんとなく自分だけではないんだなぁというのを突きつけられるのと同時に何故か劣等感を感じてるんだろう。多分その劣等感は、彼らはまだ若い。僕が彼らくらいの時にはそんなことできなかった、そんな勇気もなかったというのが劣等感につながっているのだろう。
おそらく、個人的にあまり日本人コミュニティーに近づかないのは、それも理由の一つなのだろう。いや、でもアムスの日本人コミュニティーは駐在さんメインだよなぁ。それとこれは別か?郷に入って郷に従わないのが嫌いなだけかも。

//////
超個人的な話。

弱音を吐きそうになる瞬間が増えてきた。原因も分かっていて、自分ではどうしようもできない問題の部類の一つだ。これが仕事とか、言語とか、文化の違いとかならまだ楽だったんだけどなぁ。
じっとこらえるべきか、日本に帰ることを視野に入れるべきか。後者はきっと今と同じくらいに苦しいのも分かってたりするんだよねぇ。
去年応募したアメリカのグリーンカード当たらないかなぁ。(アメリカ嫌いなのにこんなことを願うあたり、かなりキテるなぁ)

2011-05-26

マクロに潜んでいる罠

たいした物言いだがたいしたことではない。
Sagittariusで発見して、Gaucheでも再現するという不思議なバグの話。
以下のコード
(define-syntax hoge
  (syntax-rules ()
    ((_ args ...)
     (letrec-syntax 
  ((find (syntax-rules ()
    ((_ a b c)
     (next a b))))
   (next (syntax-rules ()
    ((_ a b c)
     (find a b c))
    ((_ a b)
     (print a b)))))
       (find args ...)))))
(hoge 1 2 3)
findとかnextはSSAXのマクロから取っているだけで別に名前はなんでもいい。
これを実行すると、unknown variable nextというのが出る。でも、letrec-syntaxの部分だけ取り出して実行すると動く。
原因は分かっていて、識別子の比較が弱いためにコンパイル時環境のlookupが失敗しているのだ。
不思議なこととしては、最初のhogeが展開されたときに作成される識別子は正しく作成されている(この場合は同じアドレスという意味)のに、lookup時はなぜか失敗する。
コンパイル時環境のlookupはGaucheとほぼ同じなのだが、syntax-rulesの実装はまるで違う(はず)。なのに両方でこれが発生するということは、まぁ、そこなんだろう。もしくは、syntax-rules内で予定外の識別子がrenameされたかのどちらかなんだけど。

原因を追究していたのだが、疲れたので息抜きに書いてみた。

2011-05-25

昨日の続き

とりあえず、途中経過をダンプしてみた結果、どうもSagittariusのsyntax-rulesにおけるキーワードの扱いが間違っていそうである。

どういうことか?
昨日の段階で、arg-nameが複数回出現していると書いたが、よく見るとsyntax-rulesでキーワードを設定する箇所でばっちり全部吐き出している。つまり、展開されたarg-nameはすべてキーワードなのだ。
ということは、これはR5RSだろうがR6RSだろうがきっちり通るはずなのだが、Gaucheでは通らなかったので勘違いしてしまったということである。

マクロのパターン展開をもう一回見直すことに相成り候。。。

2011-05-24

sxmlを使えるようにしたい

仕事柄、自分用の何かしらを書くのにXMLパーサーくらいは絶対的に必要になる。ということでSchemeでつかえるXMLパーサーということでSSAXをporting中。
必要そうなSRFI(13、14とか)を実装して、いざSSAXを流してみたらsyntax-rulesでおかしなエラーを出してくる。
エラーはパターン変数が重複しているというもの。
Ypsilonで試したらきっちり動く。でも、Gaucheでは同じエラー。
ちなみに、こんなsyntax-rules
(define-syntax ssax:define-labeled-arg-macro
  (syntax-rules ()
    ((ssax:define-labeled-arg-macro
       labeled-arg-macro-name
       (positional-macro-name
  (arg-name . arg-def) ...))
      (define-syntax labeled-arg-macro-name
 (syntax-rules ()
   ((labeled-arg-macro-name . kw-val-pairs)
     (letrec-syntax
       ((find 
   (syntax-rules (arg-name ...)
                   ;; ここが問題
     ((find k-args (arg-name . default) arg-name
        val . others)    ; found arg-name among kw-val-pairs
      (next val . k-args)) ...
     ((find k-args key arg-no-match-name val . others)
       (find k-args key . others))
     ((find k-args (arg-name default)) ; default must be here
       (next default . k-args)) ...
     ))
  (next   ; pack the continuation to find
    (syntax-rules ()
      ((next val vals key . keys)
        (find ((val . vals) . keys) key . kw-val-pairs))
      ((next val vals) ; processed all arg-descriptors
        (rev-apply (val) vals))))
  (rev-apply
    (syntax-rules ()
      ((rev-apply form (x . xs))
        (rev-apply (x . form) xs))
      ((rev-apply form ()) form))))
       (next positional-macro-name () 
  (arg-name . arg-def) ...))))))))
問題なのはarg-nameが2回出現していること。仮に展開されるとしてもarg-nameは同じものを指すので、展開後もパターン変数が重複する。仕様書を完全に理解してないけど、これはsyntax-rulesの動作として正しい。個人的に気になるのは、Ypsilonではなぜ動いたのかということと、他のR6RSの実装でもこれは動くのかということ。(もし他のR6RSの実装でも動くのなら、ちと考えないといけないかもしれない)
っで、sxmlをライブラリとして持っているGaucheはなぜ動いたのかというところを探ってみたところ、単純にバージョンが古かった。最新版といっても2004年ととても古いのだが、Gaucheのはさらに1年古い2003年のもので、make-parserはdefine-macroで書かれていた。
一応最新版と思われるbiglooで動く実装を覗いたら、そちらもdefine-mecroで実装してある。う~ん、define-macro自体はあるし、er-macro-transformerでの書き換えも非常に楽なんだけど、どうしたものだろう?
とりあえず他のも見てみるか。

2011-05-20

VCでのコンパイルが通った

__imp_の魔の手に苦しんだが、一応コンパイルが通った。
ってか、__impl_って同考えてもVCの不具合にしか思えないくらいひどい仕様だ。これを使って開発しようという気をごっそりともってく、かなり高等な武器だともいえるか。
R6RSのテストも既知のものを除いて通らないものは1つだけという優秀さであった。
通らなかったのは、UTF16のトランスコーダーが返すEOLでcrlfが期待値なのにlfを返してるというもの。
あんまりまじめに見てないが、まぁ、割と簡単に直るだろう。
そろそろバージョン0.1.0のリリースも近いか?

2011-05-19

かなりいいところまで来た感じ

RacketのR6RSテストのほぼすべてが通るようになった。
とりあえず通らないテストとしては、bound-identifier=?のテストの1つと、contribのテスト1つ。contribのテストは多分syntax-rulesがsyntax-caseのサブセットじゃないと通らないんじゃないかなぁと推測。
Sagittariusではsyntax-rulesはexplicit renamingで実装されているのでまぁいいかと。
bound-identifier=?のはそこまで厳密にrenamingが行われていないのと、まだまだsyntax-caseの実装が怪しいのとで原因不明。そのうち直ったらいいなぁとは思うが、この手続き自体あまり使わないので放置になるかな。
もう一つ、別環境でやったら通らなかったテストが、ポート周りのテストでstring->bytevectorとbytevector->stringを使ってるやつ。ファイルを介してテストを行うので、改行コードが処理系内部の改行コードとして処理されて通らない。ファイルを介さなければ普通にでる。気が向いたときに直そう。

ちょいちょい気になるのが、多分どこかでメモリ破壊を起こしてるんだろうなぁという出力結果が出るときがあるのだが、どこだ分からない上に、デバッガ使うと辿れない系のやつ。
見つけ次第つぶしてるけど果てしない。

ここからは愚痴。
ついでにVCでもコンパイルしようとVisual Studio 2010をインストール。っが、VCってC99に対応してないのね。結構手直しが必要になってる。特にmath.hのINFINITYとNANが面倒。あと、off_tのサイズが違うのでどうしようかな。off_t使ってるとこを全部int64_tにした方がいいだろうか?

2011-05-08

(再)letrec-syntaxにはまる

実際にはlet-syntaxだが、どちらも同じなので。
あんまりR6RSの仕様書をまじめに読んでないことが分かってしまうのだが、こんなコードにはまる。
;; (1)
(let () 
  (let-syntax ((def (syntax-rules ()
        ((def stuff ...) (define stuff ...)))))
    (def foo 42))
  foo)
;; (2)
(let-syntax ((def (syntax-rules ()
      ((def stuff ...) (define stuff ...)))))
  (def foo 42))
foo
R5RSでは上記のコードは不正になる。let(rec)-syntaxはおそらくスコープを作るのだろう。(Gaucheで確認しただけで、R5RSを読んだわけではない)
っが、R6RSではこれはOKで、let(rec)-syntaxはbeginと同じなのだそうだ。なので、(1)の場合は単なるinternal defineに展開されると考えればいいのだろう。
explicit phasingでlet-syntaxが展開された後のことを考えればそうなのかもしれないが、(2)のケースを考えると納得がいかないなぁ。

どちらにしろ、これは直さないと。でも、とりあえず先送りにしよう。こんな書き方することはないだろうし。

2011-05-03

Call/ccの実装が甘い

R6RSテストを通そうと足掻いているのだが、いまいち上手くいかない。
現在問題になってるのは、Cで実装されたassertion-violationがCのスタックを食いつぶすこと。
単発なら問題になることはないのだが、テストケースでは&assertionが発生してもテストを継続するため、例外 -> ハンドラ -> 例外 -> ハンドラ 以下続くとなりCのスタックを食いつぶす。
なぜこれが発生するかというと、dynamic-windがCで実装されていてかつ、call/ccがSchemeレベルの継続しか捕捉しないため、上記のようなC→Scheme→C→Schemeといった交互にレイヤーが変わるようなものに対して、継続が呼ばれた際にSchemeのスタックは戻すけど、Cのスタックはつぶされたままということになる。(のだと思う)
(Ypsilon、moshはdynamic-windがSchemeレベルで実装されているのでcall/ccで上記の問題は起きないと予測。Gaucheはそれように継続を捕捉した際にCのスタックもjmpbufという形で捕捉している、と思う)

解決方法はおそらく2つあって、dynamic-windをSchemeレベルにする、または継続を捕捉する際にCの継続も捕捉するのどちらかになるのかと。
とりあえず、後者かな。現状回避だけ見れば前者が早いのだけど、もう少し先を見据えると、dynamic-windはCで実装されててほしい気がする。

2011-05-01

Queen's Day

昨日はQueen's Dayでした。日本でいう天皇誕生日です。
っで、フリーマーケットがあるので情報収集(たまには日本語を話したくなるともいう)も兼ねてアムステルダム南駅周辺に繰り出してみました。
こんな感じで適当に場所取りして物を売ってます。
まぁ、メインはアムス中央なのでここは割と閑散としてます。
適当に物を買いつつ、近くに日本食品を扱ってたりするスーパーはないかとか聞いたり。
まぁ、僕はあまり社交的ではないので適当ですが。後、この辺は日本人の駐在さんが多いみたいで、なんとなく空気が違った感じがしたというのもあるけど。
(自身のコミュニティからあまり出てこない感じ?)

適当に歩いた後、ついでにテレビでやっていた日本スーパーを探してみることに。
意外と近くにあったけど、さすがに閉まっていた。
来週行ってみることにする。

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

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なんですけど)

2011-01-12

ワイド文字列

いろいろやってて壁にぶち当たった・・・
C言語で文字列を扱うことがこんなに面倒だとは、知ってたけど改めて痛感。
char = 1 byteはいいとして、
wchat_t != 4 byte ってか処理系依存って結構厳しい。
UCS4を内部エンコードに使いたかった(すでに過去形)のだが、WindowsのVCとCygwin GCCだとwchat_tは2byte。(Linuxだと4byteらしいけど、試してない)
マクロで
typedef wchar_t ucs4char;
#define UC(str) L##str
なんてことしたかったんだけど、無理になった・・・orz
そもそも
typedef int32_t ucs4char; /* 符号付 4byte(EOFは大抵-1だし) */
static const ucs4char msg[4] = {0x3042, 0x3044, 0x3046 0x0}; /* あいう */
static const char* cmsg = "abcde";
ってのがアセンブラ上だとなんかあんまり美味しくないようになってる。こんな感じで。
L0  .long 0x3042
    .long 0x3044
      :
_msg .long L0
     .def __somewhere
L1  .ascii "abcde\0"
    .text
_cmsg .long L1
なんか、静的に配列確保してて(そういう宣言だから当たり前だが)、あんまり静的な文字列な感じがしない。

あと、C内部で文字列を扱う際に、C文字列からUCS4変換する必要が出てくるので、文字列のコピーがどうしても必要になり、アロケーションが走る。使い捨ての文字列とかにアロケーションは走ってほしくない。

Ypsilon方式にするか。ファイルのエンコーディング -> UCS4(中間表現) -> UTF8(内部文字列)とするとCで使ってる文字列はそのまま流用できそう。
改修がすごく広範囲にわたるが今のうちにやったほうがいいだろうなぁ。

2011-01-08

Boehm GCを読む

正直涙が出そうになっているが、現在の所分かった(つもりでいる)部分のメモ。

    基本的な部分
  1. ヒープとして渡されるポインタはヘッダー情報を保持していない(ある意味当たり前)
  2. ファイナライザはオブジェクト(ここではポインタ)に持たせず別に管理している(finalizable_objectを格納するハッシュテーブル)
  3. ヒープ内部はOSのページブロック(基本4KB)ごとに分けられている(ちと不安)

    曖昧な理解の部分
  1. GCのヒープはGC_arraysという構造体で一括管理してるっぽい。
  2. top_indexとかbottom_indexとか2KBくらいの配列を確保してるけど、この中に実際のヒープのヘッダーが入ってるっぽい。

あ、でも
struct hblkhdr
{
  struct hblk *hb_next;
  struct hblk *hb_prev;
  struct hblk *hb_block;
  /* 以下略 */
};
struct hblk
{
  char hb_body[HBLKSIZE];
};
/* HBLKSIZEは基本4KB */
なんてなってるから、ヘッダーにメタ情報を持たせて(使える領域とか、どんなオブジェクト用かとか、残りブロックサイズとか)、ページブロック以下のサイズのオブジェクトに対してはhb_blockからみ使用部分を割り当てるなんて方法なのかも。
可変構造体にしないのは、最大限にヒープを使うためなのか、可搬性のためなのかどっちなんだろう?

2011-01-04

これってOK?

C言語でこんなのって合法?
static int s_value[5] = {1, 2, 3, 4, 5};
struct rec_t {
  int v[1];
};
static struct s_rec_t
{
  rec_t v[1];
} myth = {
  { s_value }
};
用は構造体の初期化だと思うんだけど、rec_tがint*なら合法なのはいいとして、この場合だとどうなるんだろう?
そのまま見ると1個しかない配列に対して5個入れてるから違法臭いけど、ポインタ自体を書き換えるのであれば合法っぽくもある。
実際、
struct string_t
{
   int size;
   char value[1];
};
---
string_t *s = (string_t*)malloc(sizeof(string_t) + sizeof(char)*10);
strcpy(s->value, "abcdefghi");
s->value[10] = '\0';
なんてのは合法なんだよね。
(いや、仕様書を確認したわけじゃないけど、よく見るテクニックだからそう思ってる。実際char[1]をchar*にするとセグるし、当たり前だが)
ただ、この場合だとポインタを書き換えるのではなく、連続したメモリという扱いになるのかな?
最初のケースだと純粋に書き換えてるから、うっかり鼻から悪魔が出てきても文句が言えなさそうな気はするが。
う~ん。

2011-01-01

謹賀新年

あけましておめでとうございます。

旧年はお世話になりました。本年もよろしくお願いいたします。

去年(一昨年からか?)やってる個人プロジェクト、まだあんまり形になってないけど、今年中にはなんらかの形にしたいなぁ。
個人的にもう少しな感じがしてる。(気が変わって作り直しをしなければ。何度やったか・・・)

今年はいい年になりそうな気がする。

2010-12-29

続 C言語でオブジェクト指向

バスに揺られた帰り道に思いついた。
忘れないうちにメモしておこう。

unionを使えばいいのかもしれない。
よくよく考えてみれば、設計の段階で回避できる問題なのだからこんな感じにしたらいけそうな気がする。
(対象はSchemeのポート周り)
struct Port
{
  int type;
  int direction;
  int (*close)(Port*);
  union {
    struct BinaryPort *bport;
    struct TextualPort *tport;
    struct CustomPort *cport;
  } impl;
};
typeでバイナリ、テキスト、またはカスタムポートか判別。directionでIN/OUTの判別。実際のポートの実装はimplで行って、closeとかすべてに共通しそうなのは上位に入れる。
(どうせ、そうは行ってもそれぞれのcloseを呼ぶことになりそうな気はするので、もう少し練る必要がありそうだ)

メタクラスも考えたが、一朝一夕ではいい案が出ないのと、Scheme内で使うところまで考えないとオーバースペック(苦労に見合わないとも言う)になりそうなのでとりあえず却下。
(Glib、Gaucheのソースを見たけど結構大変そうだったので。いろいろ魅力的ではあるが、自分の手に余りそうだし、recordを使えば一応クラスっぽいのも定義できるのでという理由)

明日この方向で実装を再開しよう。
ポート周りが終わらないと始まらない辛さ・・・

C言語でオブジェクト指向

ただいま絶賛挫折中・・・orz

その昔(といっても2ヶ月くらい前か?)途中で開発方針変えたため放棄したC++のソースをCに移植してる最中でぶつかった壁。
まだぶつかってるので躓いてる壁か?

単一クラス、振る舞いは変わるが継承、多態はないのなら、こんなのでいける。
typedef struct ObjectRec Object;
struct ObjectRec
{
  int x;
  int y;
  int (*squre)(Object*);
};
こんなことして、適当に関数ポインタに関数を突っ込んでやればいい。
たとえばこんなの。
static int realSqure(Object* o)
{
  return o->x * o->y;
}

static int fakeSqure(Object* o)
{
  return o->x * o->x * o->y * o->y;
}

Object* makeObject(int x, int y)
{
  Object* o = (Object*)malloc(sizeof(Object));
  o->squre = realSqure;
  o->x = x;
  o->y = y;
  return o;
}

Object* makeFakeObject(int x, int y)
{
  Object* o = (Object*)malloc(sizeof(Object));
  o->squre = fakeSqure;
  o->x = x;
  o->y = y;
  return o;
}
これで、同じo->squreなのに違う関数にアクセスできる。
この辺まではいいんだよ。昔から使ってたから。問題は継承が絡んでくると意味が分からん。
vtable使うか、メタクラスを別に作って気合でアクセスするか。
(多分、メタクラスを使った方が後々いい気がする。GObjectとかを参考にするか)

くそ、C++でかければこんなことで悩まないのに・・・
みんなDLLが悪いんだ!

2010-12-25

クロワロタwwwww

性の6時間を正すために6時間正拳突きをしようと思う。某巨大掲示板に立ったスレをまとめたもの。

クソ笑った。あほすぎる。でも、これ日本にいてリアルタイムで発見したら大阪までスネークに行ってたかもw
いや、どちらかといえばリア充寄りだと思うけどね、僕。
これだけ行動力があるのなら、もう少し建設的なことに使えばいいのに、とも思ったが。
(別に彼女を作るとかじゃなくて、勉強でもいいと思うし、昨今の政治家に対してのデモとか)

でも、個人的には愛するべきあほだと思う。

そうそう、Merry Christmas!

2010-12-22

C++/Cで書き始めたい

だいぶ自前Schemeがまとまってきたので、そろそろC++かCで書き始めようと思う。
コンパイラ(+その周りのライブラリ)はコンパイルされたコードをC(多分CよりなC++)にコンバートすればいいとして、
(それでも、ライブラリのインポートとか識別子どうしようとか問題はあるけど)
どこまでをCで書いて、どこからをC++で書こうか迷い中。

迷う理由としてはこんな感じ。
  1. C++だとバイナリ互換がない、つまりアプリケーション組み込みに向かない
  2. C++にはtemplate、class、関数オーバーロードなどCにはない機能がある
1.はアプリケーション組み込みをするのかという話にもなる。でも、たとえばDLLでモジュール(ライブラリか?)を作成したいと思ったときに、CまたはC++で書くなら必要になる気がする。
(同じコンパイラ使えばいいんだけどね、実際)
2.は要らないといえば要らないが、あるとすっきりかける気がする。慣れの問題だとは思うが。

おそらく問題になりそうな部分としては、オブジェクトの扱いかなと。
結局こいつらをC++で書くと先に書いた、DLLでモジュール作成に支障が出る気がする。
Gaucheは完全にCだが、Ypsilonは一部Cで主にC++で書いてる。
見ればオブジェクトは単なるポインタで、それぞれのオブジェクト、Pairを除く、にヘッダ(単なるunsigned int)を持たせてる。
Moshは全部C++で、オブジェクトはクラスなんだけど、タグと値を保持するだけ。
(まぁ、その他便利関数が入ってるけど)

MoshとYpsilonを混ぜるのが答えになる気がする。
こんな感じで
typedef struct ObjectRec
{
  uint32_t tag;
  void*    value; //多分こいつはintptr_tとかにしないとまずい
} Object;
っで、シリアライズ可能なオブジェクトはCで書いて、PortとかシリアライズできそうにないのはC++で書けばいいかな。

そもそも、C++のABIがもっとポータルならいいのに。問題の一つは名前マングルにあると思うんだ、うん。
(try-catchの実装とかもそうか・・・)

2010-12-16

続 R6RSのライブラリ その4

理由が全然違うことが発覚した・・・orz

原因はletrec-syntaxでsyntax-rulesにキーワードを入れたら正しく動作しないのが原因だった。
マクロ展開難しすぎる・・・
(ほぼ、Gaucheのを流用してるのになぜ?)

R6RSのライブラリ その4

ライブラリというよりはコンパイラ自身の問題か。

現在自前コンパイラを一つのライブラリにしてコンパイルしようとしている。
コンパイラはGauche上で実装されているので、Gaucheが実行できるコンパイラとそれをR6RSのライブラリにしたコンパイラと2種類ある。
(別に管理するのは面倒なので、cond-expand等を用いてできる限り最小限の重複にしてる、つもり)
っで、ライブラリのコンパイラは一つのライブラリなのにサイズが100KBを超える。多分この辺で問題が発生してる(と思う)。

libraryのコンパイルの順序として、
参照名の解決(不完全実装)、import句の解決、export句の解決、bodyのコンパイルという順番で行っているのだが、
bodyをコンパイルするさ際に、イメージとしてbodyをbeginで包んでからコンパイルしている。
こうすることで1つコンパイル、実行、というのを繰り返さず、全体をコンパイルして実行という感じにできる。
っで、(多分)上記のサイズが問題になってくる。
メモリが足りてないような症状が出てる気がする。というのも中間表現をライブラリ毎にダンプした際に、コンパイラのダンプだけ途中で途切れているからだ。
(本当に途中。ダンプせずに実行するとベクターじゃなく#fだって起こられるのに、ダンプするとぷっつりと死ぬ)
これがWindows版Gaucheだからなのか、そもそもベクターであんまり巨大(といっても目視で16MBしか使ってないけど)なデータを使えない仕様なのかわからない。

解決案は多分いくつかあって、簡単なのでライブラリの分割かな。
ただ、ライブラリを分割するということは、内部にとどめておきたい機能を外部公開する必要がでてくるので、すごく嫌だ。
一つのファイルに複数ライブラリを記述して、参照解決の際の検索方針とかでJava風なライブラリ解決にすれば、実質使えないかもしれないが、ものすごく抵抗がある。
(将来的に直すということにして現状の解決ためということにすればいいのかもしないけど・・・)

さて、どうしたものか。

2010-12-15

R6RSのライブラリ その3

この話題ばかりだ・・・

展開のフェーズの話。(というよりは依存関係か)
たとえばこのコード
(library (my-lib)
    (export sub)
    (import (rnrs))
  (define (bigger? x)
    (or (> x test)))
  (define-syntax sub
    (lambda (x)
      (syntax-case x ()
 ((_ a b)
  (or (bigger? (syntax->datum #'a))
      (syntax (let ((x b))
         (- x 10))))))))
  (let ()
    (sub 10 x)))
このコード、一見何もないように見えるけど、走らせると死ぬ。
一見何もないように見えるという段階でR6RSのライブラリについて理解してないのだが・・・orz
問題は、subの中で使われているbigger?がフェーズ0でしか参照されないこと。
subが展開されるのはひとつ前のフェーズ1なので、単純にunbound variableな例外を投げてくる。
これを解決するには、bigger?を別ライブラリにして、expandで読み込む必要がある。

まさにこれにはまっていて、
自前実装のコンパイラにライブラリを実装して、R6RSのライブラリにコンバートしてコンパイルなんてことをやっているのだが、
依存関係の解決が面倒くさすぎる。
たとえば、こんなコード
(define something 10)
(define-macro (generate)
  `(make-vector ,(- something 5)))
(define generated (generate))
こんな感じのをライブラリにするとなると、somethingは外出しにしないと上記の理由で死ぬ。
というか、すでに死んでいる・・・
(逆に考えれば、意外と適当に実装したのに、その辺もうまいこと動いているということだが・・・)

これはライブラリの仕組みが悪いのか、Schemeにマクロがあるのが悪いのか(そもそも良い悪いの問題ではないと思うが)
わからないけど、あまり相性が良くない気がする。
プログラマがいろいろなことを気をつければいいのだけど、R5RSで書いてて、R6RSにコンバートするって時に(まさに今)非常に不便・・・

2010-12-14

続 R6RSのライブラリ その2

よく考えたら(define id expr)の形式で定義されるidは自前VMだとライブラリをプロパティとして持つので、
そこを参照すればいいことに気づいた。
(もともとそのためのものなので早く気づけよ)

とりあえず、importのforキーワードについてはガン無視することにした。
あまりに理解して無さすぎなのと、明確にマクロ展開時((meta 2)以降はそれ以前になるの?)とコンパイル時と分かれているわけではないので、
実装しても煩雑になる上にあまりメリットが享受できそうになかったから。(単なる言い訳)

いい加減ながらライブラリの実装がほぼ完了。あとはバージョンを残すのみ。
でも、バージョンなんてどう管理すんだ?ということで少し整理。
現在のライブラリの構造。
top-libraries - 単なるハッシュテーブル
library       - name, imported, exported, tableを持つクラス(もしくは構造体)になる予定
                (現在は単なるベクター)

構造として
top-libraries = (lib1 => (lib1 instance)
                 lib2 => (lib2 instance))
こうなってるので、このどこかにバージョンをねじ込む必要がある。

案1:
もう一枚かませる。こんな感じ。
top-libraries = (lib1 => (version1 => (lib1 v1 instance)
                          version2 => (lib1 v2 instance))
                 lib2 => (version1 => ... ))

案2:
キーにしてる名前にバージョンをくっつける。
top-libraries = (lib1version1 => (lib1 v1 instance)
                 lib1version2 => (lib1 v2 instance))
                 lib2version1 => ... )

案3:
そんなことよりカラオケ行こうぜ!
3は無いとして(当然)、2だと微妙にメモリ消費が少なくなる気がするけど、バージョンマッチで死ぬ気がする。
1は現状の構造をいじる必要があるので、少し大掛かりになりそう(そうでもないが)

あぁ、そもそも、キーを(name version)みたいにして、やればいいのか。
(rnrs (6))みたいな例だと(rnrs (6))ってそのままになるな。
(com hoge fuga)ってのだと、適当にバージョン振る必要があるから、まぁ1だろう、こうなる?(com hoge fuga (1))
ということは、バージョンが無いものに関してはバージョンを振って、あるものはそのままキーにすればいいのか。
っで、参照する際に名前とバージョンを解決すればOKと。
とりあえず、この方法で行ってみよう。

どうでもいい話題で、export-allなんてのを作れないかなとか考えていたのだが、
結構大変そうだなぁということに気づいた・・・
importしたシンボルはまぁいいとして、中で定義されてるのを引っ張り出すのが大変そう・・・
でも、rnrsとかの巨大ライブラリを書くときに、export句に全部書き出すのって大変じゃね?っていうだけの話。

R6RSのライブラリ その2

前回の投稿にコメントをいただいて、ちょっと舞い上がっていたり。
(と同時に、Googleか何かの検索エンジンで調べた結果、役立たずなブログにぶつかったぞ、この野郎!と思われてないか不安にもなったり・・・)

自前実装で、簡単なimportとexportを実装したら不思議な現象(いや、原因はわかっているが)に出くわした。
R6RSのライブラリのフェーズの部分というかimport句の部分なの(か?)
前回syntax-caseで書いた部分、
(library (my-lib2)
         (export sub)
         (import (for (my-lib1) expand)
                 (rnrs))
  (define-syntax sub
    (er-macro-transformer
     (lambda (form rename compare)
       (or (bigger? (cadr form))
    `(let ((x ,(caddr form)))
       (- x 10)))))))
(library (my-lib3)
         (export result)
         (import (my-lib2)
                 (rnrs))
  (define (result x)
    (sub 10 x)))
(import (my-lib3)
        (rnrs))
(display (result 10))
my-lib2は展開するためにbigger?をimportしてる。
っで、これが実際に呼ばれる部分はmy-lib3内なので、問題が起きる。
(er-macro-transformerをsyntax-caseの代わりに使ってるからかもしれんが・・・)


書いてる途中で、単に名前解決の仕方がおかしいだけということに気づいた。
考えをまとめるのに、何かに書くというのは有効であるw
my-lib3読み込み → マクロ展開※1 → ライブラリコンパイル
という流れで、※1の展開時にmy-lib2内でexportされてないけど必須になるbigger?の解決を行えばいいのだろう。
一時的にmy-lib3内に取り込んで、展開終了時に開放すればいいか?
まじめにフェーズを実装すればいいんだろうけど、大変そうだしなぁ・・・(よく理解してないし。。。)

2010-12-13

R6RSのライブラリ

とりあえず、ここを読んでからR6RSを読んでみた。
まぁ、理解できたが、じゃあ既存の実装はどうなってるの?と思い調べてみた。

調査対象:Petite Chez Scheme、Ypsilon、mosh(nmosh)
調査プログラム
(library
    (my-lib1 (1))
    (export bigger?)
    (import (rnrs))
  (define (bigger? x)
    (or (> x 10))))
(library (my-lib2)
    (export sub)
    (import (for (my-lib1) (meta 1)) ; run expand (meta 0) (meta 1) (meta 2)に適宜変更
     (rnrs))
  (define-syntax sub
    (lambda (x)
      (syntax-case x ()
 ((_ a b)
  (or (bigger? (syntax->datum #'a))
      (syntax
       (let ((x b))
  (- 10 b)))))))))
(library (my-lib3)
    (export result)
    (import (my-lib2)
     (rnrs))
  (define (result x)
    (sub 10 x)))
(import (my-lib3)
 (rnrs))
(display (result 10))
こんなの。特に何の意味もないプログラムだが、フェーズを調べるには必要十分なのでOK。

で、結果。
run:
petite: 0
Ypsilon: 0
nmosh: error bigger?がない
expand:
petite: 0
Ypsilon: 0
nmosh: 0
(meta 0):
petite: 0
Ypsilon: 0
nmosh: error bigger?がない
(meta 1):
petite: 0
Ypsilon: 0
nmosh: 0
(meta 2):
petite: 0
Ypsilon: 0
nmosh: error bigger?がない

見た感じとして、Petite、Ypsilonはフェーズ関係をガン無視してるくさい。Shibuya.lisp #2か#3だかの資料によると、バグくさいのも実装したと言っているので、意図的?なものかもしれない。Petiteはよく知らん。
逆にnmoshはこの辺の宣言がきちんとされていないとまずいみたい。これはAndre Van Tonderのexpanderがそういう実装なのだろう。
この辺は仕様書に明確に書いてあるので、nmoshが正解なのだろうが、そんなもの考えてプログラム書きたくないなぁと思うとYpsilon実装にした方がいいのか?

2010-12-05

昨日の風景

今日は3度と暖かいので、雪が融けてきてる。いいことだ。

ライデン中央系の様子。
どこが道だか分からんw

近所の川(というか溝というか運河というか)の様子。
どこが水だった場所でしょう?
正解は中央部分。木の柵に見えるのは橋なのでその周りの雪は水だった場所です。
今は融けてるはず。(今日は確認して無いので不明)

今週からは暖かいはずなので、ちょっと一息といったところか。

2010-12-01

寒い!!

今週くらいから急に、しかもとてつもなく寒くなった。
現在午前7時、気温-6度!!
天気予報によると、風が強いので体感は-20度(!?)くらいらしい。

ようこそミニ氷河期へ。
地球温暖化とはいったいなんだったのか・・・

2010-11-15

メジャーデビュー決まりました

Mixiで変なバトンを踏んだので・・・
これ、マイミクの部分どうすればいいんだよ・・・
しかも、足跡残らねえよ・・・

内容は以下。
☆☆☆☆☆☆☆☆☆☆☆☆

バンドバトン♪♪

見てしまった人は必ずやること♪

足跡に残るので逃げられませんよ♪

タイトルは『メジャーデビュー決まりました』にすること♪

見た以上は必ずコメントすること♪



♪本名は?

⇒外部ブログなのでさすがに伏せさせてくださいm(_ _)m

♪ステージネームは?

⇒ねえよ

♪担当パートは?

⇒Topテナー

♪そのパートを選んだ理由は?

⇒低音が出ないから、High Cとかその辺の音が出る人があんまりいないから

♪メインで使ってる楽器はどんなの?

⇒ファルセットと実声の中間

♪それを選んだ理由は?

⇒高音をきれいに出すにはと試行錯誤した結果、あんまり力まずそこそこ張れるから

♪その楽器のPRポイントは?

⇒High G(ソプラノのG)くらいまでがんばれば出せます(使い物にはならんが・・・)

♪歴はどれくらい?

⇒そろそろ10年か(でも、ここ2年はやってないからもっと少ないか)

♪初めて完コピーした曲は?

⇒ゴスペラーズの星屑の街かな

♪その曲を選んだ理由は?

⇒アカペラの曲で有名なのは少ないのよ

♪憧れのミュージシャンは?

⇒昔はパバロッティ、今は誰だろ?

♪好きなミュージシャンは?

⇒たくさん

♪好きな曲を1曲挙げるとすると?

⇒一曲なんて無理です・・・

♪好きなジャンルは?

⇒最近はHipHopとかも聞くようになったし、おそらく演歌以外すべてかと
でも、あんまり意味不明なジャンルは聞かない

♪今バンド組んでる?

⇒組んでない。
オランダ在住で、アカペラやりたい人やりませんか?w

♪バンド組んでる人はバンド名を教えて下さい

⇒組んでない

♪プロは目指してる?

⇒プロってなに?

♪ライブの失敗談はありますか?

⇒結婚式で歌ったときに、オルガンの演奏がまったく聞こえず、意味不明になった

♪担当パートの楽器にいくらぐらい遣った?

⇒無料、タダ、Free、Gratis

♪生まれ変わってもバンドをやるならパートは何がいい?

⇒楽器を使うパートかな・・・でもアカペラも楽しいんだよね・・・

♪付き合う前の好きな異性をライブに呼んだことはある?

⇒ない

♪その異性とはいい感じになった?

⇒ない

♪その異性と今は?

⇒何の質問だこれ?

♪このバトンを見た人は必ずやらなければなりませんが、中でも特にやってほしいマイミクを5人挙げて下さい

⇒マイミク少ないのに・・・
Rogさん
Zestさん
まっけんじーさん
ラフマさん
うまmiさん

バンド組んでない人は、架空のバンドを想定してくださいm(_ _)m
上三人はB.G.M.でOKだと思います。

♪最後になりますが、音楽は世界を救うと思いますか?

⇒戦闘なんてくだらねぜ、俺の歌を聞け~!!!
こうですか?

以上

☆☆☆☆☆☆☆☆☆☆☆☆

2010-11-12

syntax-case続き

とりあえず、こういう方針でいこうという考えをまとめておく。

syntax-case自体はコンパイラとは関係ない(ないことはないが)、ライブラリとする。
define-syntaxで定義された構文は変換器を返し、変換器が変換する。
(Gaucheはそうしてると思う。ソース見る限り・・・今のところsyntax-rules限定っぽいけど)
define-syntaxで定義された構文にS式が与えられた場合、構文オブジェクトとしてすべての引数を与える。
こんな感じ?
(define-syntax sample
  (lambda (x)
    (syntax-case x ()
      ....)))
(sample 1 2 3) ;; <- この1 2 3っていうのがsyntax-caseによって処理されるために構文オブジェクトになる
ということは、マクロを展開する際に、S式をいったん構文オブジェクトにする必要がありそう。 これで、syntax-caseを定義するとすると
(define-syntax syntax-case
  (lambda (x)
    ... ;; いろいろ定義がいりそう?
    ;; x は構文オブジェクト。matchはAndrew Wrightみたいなの(構文オブジェクトにも対応)
    (match x
      ((_ e ((? literal? literals) ...) clauses ...)
        ...)))) ;; きっといろいろする
っで、こいつ自体が変換器なので、syntax-rulesはこう書いて
(define-syntax with-syntax
  (lambda (x)
    (syntax-case x ()
      ((_ () e1 e2 ...)             (syntax (begin e1 e2 ...)))
      ((_ ((out in)) e1 e2 ...)     (syntax (syntax-case in ()
                                              (out (begin e1 e2 ...)))))
      ((_ ((out in) ...) e1 e2 ...) (syntax (syntax-case (list in ...) ()
                                              ((out ...) (begin e1 e2 ...))))))))
(define-syntax syntax-rules
  (lambda (x)
    (define clause
      (lambda (y)
        (syntax-case y ()
          (((keyword . pattern) template)
           (syntax ((dummy . pattern) (syntax template))))
          (_
           (syntax-violation 'syntax-rules "Invalid expression" x)))))
    (syntax-case x ()
      ((_ (k ...) cl ...)
       (for-all identifier? (syntax (k ...)))
       (with-syntax (((cl ...) (map clause (syntax (cl ...)))))
         (syntax
          (lambda (x) (syntax-case x (k ...) cl ...))))))))
syntax-rulesで定義された構文は 構文 -> syntax-rules変換器 -> syntax-case変換器 -> ごにょごにょ という感じになるはず。 こんなのは
(define-syntax print
  (syntax-rules ()
    ((_ o)
     (begin (display o) (newline)))
    ((_ o1 o2 ...)
     (begin
       (display o1)(newline)
       (print o2 ...)))))
(print 1 2)
こうなる?
(print 1 2) -> (transformer syntax-rules '(syntax-object (print 1 2)))
: with-syntaxは略
-> (transformer syntax-case '(syntax-object ...#;多分この辺にsyntax-rulesで作られたtempleteが入る (print 1 2)))

正しいのかよくわからん。その上、どう実装していいのかもよくわからん・・・

syntax-caseの実装

Schemeの話。

マクロの展開を実装しようとした際に、syntax-caseがどうしてもキーワードになる。
これはなんだ?
いや、何かはわかっているんだけど、R6RSの仕様書を見ると、こいつはライブラリだと書かれている。

っで、いろいろなR6RS準拠の処理系で試したところ、
どうもこいつはキーワードっぽい動きをする。(defineとかlambdaとか見たいな)

ということは、組み込みか、(define-syntax ...)で定義されたものかという気がする。
っで、仕様書にはライブラリと書かれている・・・
syntax-rulesとかはsytax-caseで定義できるみたいだが、
syntax-caseはどうやって定義するのだろう?
こんな感じ?
(define-syntax syntax-case
   (lambda (form literal rules)
     ...))
っで、適当にパースすればOK?

ちなみに、psyntaxはよく知らないけど、
YpsilonとかAndre van Tonderのexpanderとかだと割りと組み込みみたいな書き方してる。
(コンパイラが持ってるわけじゃないからライブラリ?)
細かいこと考えなくてもいい?
う~ん。

2010-11-05

【尖閣ビデオ】見た!!!!

昨日の夜(といっても日本時間なら午前5時か6時くらい)にYoutubeにアップされていたビデオを見た。
中国は真っ黒です!!

これみて、コツンと当たったとか、日本側が悪いとか言ってるアホ議員がいるということが正直信じられない。
個人的な意見だけど、これ逆の立場だったら中国は最大級の外交カードとして使うだろう。
そもそも、領海侵犯してる漁船が体当たり+逃亡なんてロシアとかアメリカに対してやったら船がこの世から消えてるレベル。

この動画の2分くらいのところから:

明らかにぶつけにきて、かつ逃亡。

こっちの方は海保の船「みずき」が黒煙を上げてる:


これで
こんな穴が船体右側に空くわけがない!!!
ってか、仮に先端部が当たってあいたとして、真四角の穴が開くわけないだろ!!

これで船員を釈放した無能議員とか死んでいいんじゃね?

2010-11-02

Infoseekが終了した

まぁ、2ヶ月くらい前から知っていたことではあるが、自分の過去のHPも一緒に消えた。
(メンテナンスしてなかった上に、FTPのパスワード忘れちゃったのでどうにでもなれ状態ではあったが・・・)

困るなぁと思うのは、自分のとは違って有益な情報を載せてるサイトが結構多かったので、移転せずに消えてしまったらいやだなぁということ。
有料のサービスは残るとのことなので、有益サイトがそっちだったらいいなぁ・・・

2010-10-28

Movie: It Could Happen to You(邦題:あなたに降る夢)

1994年なんだこれ・・・
実話をヒントに作られた映画。ジャンルはラブコメでいいのかな?
あらすじと実話は適当にググってください。

感想。ニコラス・ケイジ演じるチャーリーの駄目男っぷりと、その妻の強欲っぷりが素敵な映画。
ブリジット・フォンダ演じるイヴォインヌの薄幸ぶりもかな?
いや、まだ観てるんだけど実は、今のところの感想として、宝くじは結婚してから買っては駄目だね。当たったらいろいろ火種にしかならない気がする。
ってか、ニューヨーカーとマスコミは主人公2人に振り回されすぎ。宝くじが当たったからといってそこまで追跡されんと思うぞ。
(書いてる途中で終わった)

なんというか、女が腐ったような男(イヴォインヌの元夫)とか嫌いなタイプの人間が出てくる映画ってあまり好きじゃなかったり・・・
借金背負わせて逃げたくせに、2億入ったから戻ってくるって、どの面下げて(ryって感じ。

個人的に最後のお約束は要らないんじゃないかなぁとは思った。別に強欲妻は勝ち逃げでもよくね?金手に入れるために裁判して、60過ぎのおじいちゃんと結婚までしたんだから?
ま、お約束がないといかんのだろうけど、ハリウッド映画って。

見る価値は、野郎だけでなら0かな。

2010-10-20

寒い!!!

先週くらいから急激に寒くなった。
最低気温が3度とかある・・・

んで、今日は雹が降ってきた!!!
どうやら上空には寒気団があるくさい。

まだ10月なのに冬の到来を感じる。
12月とかになったら氷点下確定コースかなぁ?
-10度とか去年だけのことだと思いたい・・・

2010-10-15

契約更改の話

僕自身の契約更改は順調に終わり、無事に正社員になったわけだが、
そうでは無い人もいたという話。

実際知ったのは今日(昨日?)なのだが、僕より二週間早く入社した人が8月の段階で契約延長(もしくは正社員になる契約)をしないということだった。
そういえば今週の頭から姿を見てないなぁ、と思っていたらその通知のメールと、PC撤去が同時できた。
(ちなみに、席は僕の目の前)
理由は知らない。あまり一緒に仕事したことはないが(一時期同じプロジェクトにいたくらい)、可もなく不可もなくという感じの仕事ぶりだった気がする。
(個人的には汚いコードを書くなぁとは思っていたが・・・)

まぁ、理由は以下のどれかなのは自明で、
・解雇
・自主退職
ってか大別するとこの2つしかないわけで。

8月の時点ですでに話し合っていたということは、おそらく後者かな?
僕が契約更改の話を受け取ったのは9月に入ってからだし。最近まで何かのプロジェクトに参加してたみたいだし。
もし、解雇だとしたら、当然それは僕だったかもしれなくて、なんて考えるとちょっと複雑な気分であった。

2010-10-01

ハッシュテーブルの検索

超有名なデータ格納の方法の一つ。
諸事情により、自前でハッシュマップとハッシュセットを作る必要があったので、作ってみた。
理論上計算回数がΟ(1)でいけるはずなんだけど、どうもそんな感じがしない。

っで、STLのsetと自作ハッシュセットで比較してみた。
結論だけ言うと、
ハッシュセットは早いけど遅い。
なんのことだ?と思うかもしれないけどそんな感じ。
実装の都合上、衝突が起きた際に得られたハッシュ関数で得られたハッシュ値を増やして空きを探したり、
要素が存在しているか検索しているのだが、これがまずい。
無限の箱があってハッシュ値も衝突がおき得ないのならΟ(1)なんだろうけど、箱は有限。っで箱が50000とか超えた時に、存在しない値の検索をすると、ループが50000回走る。つまりΟ(n)になる。
う~ん、存在する値だとものすごく早くてそれこそΟ(1)に近い値が出るんだけど、う~ん。
衝突時にリストにしてもいいけど、メモリ管理が面倒な気がする・・・う~ん・・・

どうでもいいけど、
「Ο」これ「O(アルファベット)」じゃなくて「Ο(オミクロン)」だったのね。初めて知った^^;

契約更改

今の職場についてほぼ1年が過ぎようとしている。
契約は最初は1年契約なので、今日契約の更新の面接があった。

結果、無事正社員に昇格!
昇給もしたし、う~ん、いいことだ。

オランダだと一年で正社員になるというのは珍しいらしく、普通はなんだかんだ契約の延長だけというのが間々あるらしい。
マネージャー(日本語に直すとなんだ?部長とかそれ以上?)との面接で、
働きぶりに満足してるし、ここで働いてほしいというようなことも言ってもらえたのだが、
しかし、正直ほとんど何もしてないに近いくらい楽な仕事なのだが、
いいのだろうかと不安になる。
(もちろんやることはやっているのだが、いかんせん楽すぎる)

ま、プログラマは天職なんだということにしておこう。

iPhone

いろいろな経緯からiPhoneが今手元にある。
3Gなので一つ前のだ。

PDAかつiPodに電話がついてる感じで、正直もてあましてる感が大きいが今のところ気にいっている。

誰か、お勧めアプリを教えてくれ!

2010-09-26

Cygwinのメモリ

Cygwinだけなのか、Mingwもなのか、そもそもC++の企画なのか分からんけど、メモリの確保ではまった話。

Cygwin上のGCCで(正確にはG++)1M以上のメモリを確保して、そのメモリに生でアクセスしようとしたらセグメンテーションフォールトが起きた。
なんでだろうと思ったが、プログラム全体で見ると動いていたのでとりあえず放置していたのが、やっぱりおかしいよなぁと思って検証してみた。

検証プログラム
#include "test-a.h"
#include 
int main()
{
  void* p = (void*)new char[1024* 1024];
  printf("%p\n", p);

  test t;
  t.print();

  test *t2 = new test();
  t2->print();
  delete t2;
  return 0;
}
test-a.hはtestクラスを持ち、そのコンストラクタ内で1Mのメモリをoperator newで確保し、printメソッドでメモリアドレスをプリントする。それだけ。
実際はtestクラスの詳細はスタティックライブラリにしてある。スタティックライブラリの制限かなとも思ったので。

結果。
そもそも最初のnewで死んでた。
帰ってきたアドレスが、0x7fea0008。完全に死亡アドレスです。
理由は分からんが、アウトなんだろう。

しょうがないのでとりあえずWin32APIのVirtualAllocを使って回避。こっちならOKっぽい。
この制限があると、多き目のメモリープールとか不可能になる気がするが、どうなんだろう?
ってか、一気にメガ単位で確保しちゃ駄目ってこと?
誰か理由教えて(´;ω;`)

2011/10/25 追記
ひょっとしたらこの辺と関係あるかも=>Cygwinのヒープ

2010-09-13

英語の発音について

英語の発音で日ごろ理不尽に感じてることをちょっと書いてみる。
(なんで今更こんなことをとか自分で突っ込み)

同スペル、異発音
Houston:
/ˈhjuːstən/ ≒ ひゅーすとん と発音すればテキサス州の都市(が有名、ほかにもある)
/ˈhaʊstən/ ≒ はうすとん と発音すればニューヨーク市の通りの名前(が有名、ほかにもある)

読みにくい系
simultaneously:
/ˌsī-məl-ˈtā-nē-əs-ly/ ≒ さいみゅるてにあうすりぃ。
ちなみにsimulateは/ˈsim-yə-ˌlāt/ ≒ しみゅれいと だったりする。(個人的に前者は米語だと思ってる)。

cupboard:
/ˈkʌbərd/ ≒ かばーど。知らなきゃ読めない。
ちなみに、boardは/bord/ ≒ ぼーど なので、後半だけ見ると同スペル、異発音かも。

nature:
/ˈnā-chər/ ≒ ねいちゃー。でもこれ、naturalになると/ˈna-chə-rəl/ ≒ なちゅらる になる。

英語と米語で発音が違う系
tomato:
「これが、"とめいと"だと!」と中学に入ってまず間違いなくショックを受けた言葉の一つだと思う。でも、英語(イギリス系)だと"とまーと"と発音したりする。ちなみに、tamagoは「ためいご」ではないのであしからず。

あんまりぱっと思いつかなかった。
この手のねたは需要があるかテストもかねて投稿してみたり。

2010-09-03

Java: Preferenceクラス

Javaのことを書くなんて本当はしたくないがあまりにネタがないので。
(Schemeの方は遅々として進まん・・・orz)

仕事は当然Javaを使うのだが、APIではまった話。
Preferenceというクラスがあるのだが、こいつは設定とか値をプラットフォーム固有の方法で永続化して使いまわせる便利なもの(のはず)
っで、今のプロジェクトでこいつを使っているのだが、なんか値がおかしい。
Windowsなので、レジストリに登録されるのだが、どうも1個しか値が存在してない。
っで調べてみた。

JavaDocによると、こいつはノードを取得する際にクラスを要求するくせに、値の保存はパッケージごとに行われるということ。クラスを要求するのは、パッケージ名を取得するためだけみたい。
つまり、
foo.bar.Hogeと、foo.bar.FugaっていうクラスでPreferenceを使うと値が共有されるらしい。
この方がありがたい人もいれば、そうじゃない人もいるだろう。僕は後者なわけだが・・・

foo.bar.configなんてパッケージを作ってその下にいくつかの設定値クラスなんかを作った場合問題になる、というか僕の問題はまさにこれ。
パッケージごとに一個の永続値って需要があるのだろうか?
ドキュメントをしっかり読めば早期発見できた問題ではあるが・・・

2010-08-15

前回から1ヶ月くらい離れてるなぁ・・・

日本にいたときは便利だったなぁという話。

スーパーとかなら切り身で売ってるけど、
マーケットで魚を買うとあまり魚はきれいになっていない。
頭、内臓、鱗のことだけど。
鮮度とか安さとかならきっと上なんだと思うけど、よくて内臓くらいまでか、さばいてくれるの?
しょうがないので、包丁で鱗を落とすし、三枚にもおろす。
(身が骨の方にたくさんつくときもあるが)

この辺のサービスは絶対的に日本の方がいい気がする。
しても、追加料金取るとかざらだし。
こっちの人たちあんまり客を大切にしないイメージ。

日本が過剰サービス過ぎなのか?

2010-07-16

どれが正しいんだ?

Schemeでdefine-syntaxの実装をしないといけないことに気づき、ちょっと調査。
単にマクロ展開のタイミングの話なのかな?

(import (rnrs))
(define (print x)
  (display x)
  (newline))

(define x 1)
(define (incf x . i)
  (if (pair? i)
      (begin (set! x (+ x (car i)))
      (print "procedure")
      x)
      (begin (set! x (+ x 1))
      (print "procedure")
      x)))
(print (incf x 2))

(define (test x i)
  (print (incf x i)))
(test x 1)

(print "define incf as define-syntax!")

(set! x 1)
(define-syntax incf
  (syntax-rules ()
    ((_ x) (begin (set! x (+ x 1)) x))
    ((_ x i) (begin (set! x (+ x i)) x))))
(print (incf x 2))
(test x 1)
こんなコードを、Chez(7.9.4)、Ypsilon(0.9.6-update3)、Mosh(0.2.5)に食わせてみる。

結果。
Chezは正常終了。最後の(test x 1)で展開されると思われてincfマクロは展開されず。
Ypisilonは最後の(test x 1)でincfの定義がない(多分、マクロで上書きされたから?)と怒る。
Moshはincfが複数定義されたといって例外。

それぞれの結果はこれ。
Chez
------------
procedure
3
procedure
2
define incf as define-syntax!
3
procedure
4
------------

Ypsilon
------------
procedure
3
procedure
2
define incf as define-syntax!
3

error: unbound variable incf

backtrace:
0 (incf x i)
..."D:/home/t.kato/test.scm" line 18
1 (test x 1)
..."D:/home/t.kato/test.scm" line 29
------------

mosh
------------
Condition components:
1. &who who: incf
2. &message message: "multiple definitions of identifier"
3. &syntax form: incf
subform: #f

Exception:
error in raise: returned from non-continuable exception

Stack trace:
1. throw:
2. (raise c): baselib.scm:943
3. apply:
------------

これだけバラバラだとどれが正しいのかわからない・・・

2010-07-09

英語で仕事をするということ

最近、楽天の社長が社内公用語を英語にするという記事を読んだのと、
それに反応してソニーかどこかの人がTwitterで、そんなことするくらいなら公用語をC言語にする、などといったのを読んだので無駄に反応してみた。

個人的な意見。
まったく無駄だと思います。
日本に本社があって、社長も日本人で、働いてる人の95%以上が日本人の環境で、英語にする意味がない。こっちで働いていて、使用言語はオランダ語ではなく英語なわけだが、オランダ人同士が会議している場所だと当然オランダ語。
そもそも、怪しい英語で会議しても意味なくね?英語が喋れることが最重要事項な会社って、翻訳会社か何かだと思う。楽天はそっち系に変わるのかね?

できることなら日本語環境がいいなぁと思う人の独り言・・・

2010-07-02

街が揺れた日

その日は暑い夏の日だった。仕事帰りの私はいつもと同じ道を歩いていた。
突如凄まじい轟音とともに街が一瞬揺れた!

えぇ、その瞬間がオランダがブラジルを下したことが決定した瞬間です。
正直、1点とったのかなと思ったんだけど、勝ってました。
ブラジルにですよ。信じられん。

ブラジルに勝てたということはそのまま優勝ということもありえるなぁ。

2010-06-30

C++で書き始めた

Scheme処理系をC++で書き始めた。
(実際は片付いてない問題が多々あるのだが・・・)

とりあえず、コードがVectorで構成されているのでVectorを。あと物が動くとやはりうれしいので、Fixnumなクラスを作成。
xyzzyの参考に(パチッてとも言う)、クラスのタグ付けとか、即値の判定とか作成。
っで、適当にごにょごにょして動かす。

(+ 1 2 3)をコンパイルした結果をC++のオブジェクトに置き換えたものが動いた。
説明が長い・・・

気になる点としては、現状だとコードはベクターの中にベクターが入れ子になるように作ってあるのだが、これだとメモリー効率が激しく悪い気がする。
Schemeで書いてるときは気にしなかったのだが、C++で書いてみると一つのコードを書くのにベクターの割り当てが激しく出てくる感じ。
コンパイラを書き換えて全部フラットにするべきだろうか・・・するべきなんだろうなぁ・・・

2010-06-24

ワールドカップ

日本が3-1でデンマークに勝った!!
何が起きてるんだろう?天変地異の前触れか?

どうでもいいが、ここオランダではサッカーがあるとえらいことになる。
僕の住んでるライデンにはちょっとした広場が街の中央にあるのだが、そこにパブリックビューがあって結構な人が集まっていた。
酒が飲めればいいのか、騒げればいいのか、純粋にサッカーが好きなのかどれなのかは分からないが、街中がやかましい。
噂によると、サッカーの観戦をするために仕事を病欠する人がいるそうだ。
そんな国。

2010-06-22

letのフレーム

A正規化の話だったりする。
たとえばこんなコード(変な数字が入ってるのはα変換後だから)
(define
 tarai
 (lambda
  (x.1 y.2 z.3)
  (if
   (not (< y.2 x.1))
   y.2
   (tarai
    (tarai (- x.1 1) y.2 z.3)
    (tarai (- y.2 1) z.3 x.1)
    (tarai (- z.3 1) x.1 y.2))))
こいつをA正規形にするとこうなる
(define
 tarai
 (lambda
  (x.1 y.2 z.3)
  (let
   ((#:G267 (< y.2 x.1)))
   (let
    ((#:G268 (not #:G267)))
    (if
     #:G268
     y.2
     (let
      ((#:G269 (- x.1 1)))
      (let
       ((#:G270 (tarai #:G269 y.2 z.3)))
       (let
        ((#:G271 (- y.2 1)))
        (let
         ((#:G272 (tarai #:G271 z.3 x.1)))
         (let
          ((#:G273 (- z.3 1)))
          (let
           ((#:G274 (tarai #:G273 x.1 y.2)))
           (tarai #:G270 #:G272 #:G274)))))))))))
見てのとおりコードが増大。それだけならまだいいのだが(よくないが)、問題はコードの増大に伴ってletが出現していること。
前回、継続周りで不具合が起きることを踏まえて、letが現れたらフレームを作るようにコンパイラとVMを修正したのだが、その影響で単なるたらいまわし関数がスタックオーバーフローを起こすようになった。
原因は、この大量のlet。これだけコードが増大すれば当然VMのインストラクションも増大する。どれだけ影響があるかスタックを1000から10000にして上記の関数でベンチマークをとってみた。
4秒が14秒に・・・orz

後の最適化がしやすいようにと思ってのA正規化だが、ちょっとないなぁ・・・
今のところこいつの恩恵って、変数の寿命がわかりやすいことだけだし・・・
どうしよう。

2010-06-18

スタックポインタ、フレームポインタ

Schemeのコンパイラの話。
3impという論文のコンパイラを参考に作っているわけだが、スタックポインタとフレームポインタではまった。
(ってか、今でも解決してない)

ここにあるスタックとフレームの関係を参考にして、letのコンパイルをしたのだが、上手くいかない。
原因は分かっている。本来はletごとにフレームを作成して自由変数とかの解決をしないといけないのに、フレームを作るコストを嫌って、letが続く限り一つのローカルフレームのようにしたから。
そもそも、letではフレームを作ってないので、フレーム情報があることを前提にしているVMインストラクションでおかしなことが起きる。

どうしよう。
とりあえず、Gaucheがletをどう処理してるのかdisasmしてみた。
...
let毎にフレーム作ってる・・・
やっぱりそうするべきかなぁ?でもA正規化後ってあほかと思うほどletが増えるんだよなぁ・・・
その辺も踏まえてどうしよう。

2010-06-15

コンパイル

いろいろ弄って、letをコンパイルできるようにした。
意外と上手くいくもんだ。四苦八苦したけど・・・

っで、たらいまわし関数を動かしてみたら、10,5,0の引数で36秒かかる・・・
まぁ、schemeをscheme上で動かしてるのでオーバーヘッドとかもあるだろう。っがあまりに遅いのでできそうな高速化を施すことに。
現状リストでVMのインストラクションを書いていたが、全部ベクターに変更。でも、面倒くさがりなので、
ベクターの中にベクターを入れるといういんちき(?)をして、データ構造は特に変更しない。
勢いあまってVMにプログラムカウンタをつけてみたけど、要らん気がする。まぁいいや。

これで、一時的に5倍くらい早くなった。
次にインストラクションを今後のために数値に変更。これは逆に遅くなった。
考えられそうな理由は現状プリミティブの実装がかなり適当で、シンボルと数値の比較が一つのcond文に混在している。なので、シンボルの比較を先にしないと、Gaucheに怒られた。っで先に回したら鈍足に・・・
比較の分だけ遅くなるわね。
逆に言えば、よく使われるインストラクションは前の方に持ってくると幸せになれるか?

っで、とりあえずプリミティブをいんちきせずにコンパイルするようにしている最中。
物が動いてくるとやはり楽しい。

2010-06-14

カメルーンに勝った

ワールドカップの話。
職場が半日だれも仕事しないくらいオランダはサッカーが熱い(個人的にはどうでもいいが)
職場で点が入るたびに雄たけびが聞こえてくるくらい。

っで、それのあおりで日本VSカメルーンを少し見た。
あれ?勝ってる?
1-0で日本が勝った・・・

とりあえず、前評判を的確に表していたであろうコピペ。
A                              B 
南アフリカ「ガチ抽選をした結果がこれだよ!」   アルゼンチン「なんだ楽勝じゃん」
メキシコ「南アフリカ乙」                 ナイジェリア「2位ならなんとか」
ウルグアイ「南アフリカ乙」               韓国「\( ^o^)/」
フランス「実質シードワロスww」             ギリシャ「2位ならなんとか」

C                              D 
イングランド「アジアとやらせろよ」           ドイツ「そこそこの組み合わせかな」
アメリカ「微妙・・・」                    オーストラリア「2位いけるな」
アルジェリア「無理くさい」                セルビア「2位いけるな」
スロベニア「微妙・・・」                  ガーナ 「2位いけるな」

E                              F
オランダ「まぁ、おk」                   イタリア「楽勝www」
デンマーク「日本には勝つとして・・・」         パラグアイ「ニュージーには勝つ」
日本「なかなかいい組み合わせだな(キリッ」      ニュージーランド「なにこの無理ゲー?」
カメルーン「日本には勝つとして・・・」         スロバキア 「ニュージーには勝つ」

G                              H
ブラジル「1位通過するよ」               スペイン「楽勝すぐるww」
北朝鮮「どうしてこうなった!」             スイス「ホンジュラスには勝つ」
コートジボワール「1位通過するよ」          ホンジュラス「まぁ、がんばる」
ポルトガル「1位通過するよ」              チリ 「ホンジュラスには勝つ」 

う~ん、何が起きたんだろう?

ミーはおフランス帰りざんす

ということで、パリに行ってきました。
パッケージツアーというのは今までの人生でほとんど経験がないので(修学旅行等除く)それなりにいい経験になったかなと。
言葉の壁さえ考えなければ、交通費、朝食、夕食、セーヌ川のボートツアー、その他いろいろ混みで150ユーロは安いのではないかな。

パリの街は思っていた以上になじむなぁとちょっと感じた。
そこらじゅうで言われていた、犬の糞の問題は特になく、きれいだったし。

っが、街はきれいでも人は・・・
パリで運転する必要がある人はかなりの胆力が必要になるだろうなぁと。

時間がないので適当。

2010-06-09

やっつけA正規形拡張

とりあえず、オリジナルのA正規形で問題かなと思ったのが以下の点。
  1. letが引数一つ
  2. cond、letrec等の必要そうな構文がない(condはif文で書きかえれるけど・・・)
  3. quoteしたものも正規化する
ということでちょいちょい変更。

1. letが変数一つって扱い難いので複数取るように変更。(let (<binds>) <body>)というが普通のletなのでこれを取るようにし、<binds>の(変数 値)という式を一つずつ正規化後letを再構築。

2. condは
(cond (<pred1> <then1>)
      (<pred2> <then2>)
      (else <then>)
という式なので、pred1 ... pred2をこんな感じに
(let ((p1 (normalize <pred1>)))
   ; 以下predの数だけ
っでthenを正規化してcondを再構築。
letrecとletrec*はバインド変数だけ正規化してそのまま放置。とりあえずこれでいいか?

3. オリジナルは(display 'a)というのが(let ((r 'a)) (display r))ってなってたので、さすがにあほらしいかと思い、quoteは正規化しないことにした。

っで、とりあえず3impのコンパイラでコンパイルしてみた。
おぉ、コンパイルできた。
っが、コンパイラにletをコンパイルする記述はない・・・さて、考えるか・・・

2010-06-08

A正規形に切り替える

CPS変換がどうにも上手くいかない。
なんとかなるんだろうけど、涙が出そうになってきたので断念。
一応、それ以外の理由として、
  1. コードの肥大化がすさまじい
  2. 変換することによって、関数のシグネチャが変わる(継続を渡すように変更するため)
  3. ベンチマークで脅威の低速を叩き出してる
この辺がそれ以外の理由。まぁ、3番目はVMの最適化次第だと思うけど・・・
(Gauche上で動かしてるのでしょうがない)

ということで、A正規形に切り替えることにする。
A正規形はCPS変換後逆CPS変換した形に極めて近い気がする。すべての継続の結果を変数として確保するので、スタックの肥大化が問題かな?
ここが詳しい。別に論文も読むといいと思う。
論文の最後にアルゴリズムをschemeで実装した例がある。
問題はこいつはCore SchemeというSchemeのサブセットを対象としているので、いろんな部分で限定的。(letrecとかないし・・・condとかどうするんだろう?)
その辺りを自前で拡張することができればよさそうだ。できるかな?

2010-06-07

コメントの仕方

コメントの仕方が分からないという指摘が累計2件ほどたまったので(少ない)
蛇足ではあると思うけど書いてみる。

コメントしたいと思う投稿の一番下にある、数字 + コメントという(このブログだと緑)のリンクをクリックする。
するとなんとも味気ないコメント投稿画面が現れるので、大き目のテキストエリアにコメントを書き込む。
スパム防止機能があるので、コメントのテキストエリアの下にあるフィールドに画像の英数字を入力。
投稿者のIDを選択。OpenIDはよく分かっていないが、Googleアカウントがあればそれでもいいし、そんなもの無いなら名前/URLを選択し名前を入力。もちろん匿名でも構わない。
最後に投稿ボタンを押せば完了。
bloggerのコメントはきっと共通だと思うので、これで他のbloggerにもコメントができる!

さぁ、早速この投稿にコメントして練習だ!

2010-06-03

ぬか喜びだった件・・・

前述のベンチマークだが、手動CPS変換が間違っていた。
正しくはこう
(define (<=/cps x y k) (k (<= x y)))
(define (-/cps x y k) (k (- x y)))
(define tarai-cps  
  (lambda (x y z k)
    (<=/cps x y
     (lambda (b)
       (if b
    ;ここが違う
    (k y)
    (-/cps x 1 
    (lambda (x2)
      (tarai-cps x2 y z
          (lambda (t1)
     (-/cps y 1 
     (lambda (y2)
       (tarai-cps y2 z x
           (lambda (t2)
             (-/cps z 1
             (lambda (z2)
        (tarai-cps z2 x y
            (lambda (t3)
              ;ここも
              (tarai-cps t1 t2 t3 k))))))))))))))))))
(time (tarai-cps 10 5 0 (lambda (x) x)))
っで、ベンチマークの結果。
Petite Chez Scheme 7.9.4
(time (tarai-org 10 ...))
    no collections
    16 ms elapsed cpu time
    0 ms elapsed real time
    0 bytes allocated
(time (tarai-cps 10 ...))
    10 collections
    125 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    44600752 bytes allocated, including 42111448 bytes reclaimed
(time (tarai-anf 10 ...))
    7 collections
    78 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    29505120 bytes allocated, including 29499488 bytes reclaimed
(time (tarai-lambda 10 ...))
    7 collections
    78 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    29505120 bytes allocated, including 29490760 bytes reclaimed

Gauche 0.9
;(time (tarai-org 10 5 0))
; real   0.016
; user   0.015
; sys    0.000
;(time (tarai-cps 10 5 0 (lambda (x) x)))
; real   0.453
; user   0.407
; sys    0.047
;(time (tarai-anf 10 5 0))
; real   0.031
; user   0.031
; sys    0.000
;(time (tarai-lambda 10 5 0))
; real   0.422
; user   0.375
; sys    0.047
圧倒的じゃないか。。。orz
どう考えてもなしの方向っぽいです、本当に(ry

ベンチマーク

CPS変換の勉強中にANF(A-normal form)との共通点を見つけて、
ひょっとしてCPS変換しなくてもA正規化すればいいのでは?
という誘惑にかられたことから、ちょっとベンチマークとってみた。
(どっちが速度が出るか比較したかった。速い方がいいじゃん!)

使用したコードは以下
(define tarai-org
  (lambda (x y z)
    (if (<= x y)
 y
 (tarai-org (tarai-org (- x 1) y z)
     (tarai-org (- y 1) z x)
     (tarai-org (- z 1) x y)))))
(time (tarai-org 10 5 0))

(define (<=/cps x y k) (k (<= x y)))
(define (-/cps x y k) (k (- x y)))
(define tarai-cps  
  (lambda (x y z k)
    (<=/cps 
     x y
     (lambda (b)
       (if b
    y
    (-/cps
     x 1 
     (lambda (x2)
       (tarai-cps 
        x2 y z
        (lambda (t1)
   (-/cps
    y 1 
    (lambda (y2)
      (tarai-cps
       y2 z x
       (lambda (t2)
         (-/cps
   z 1
   (lambda (z2)
     (tarai-cps
      z2 x y
      (lambda (t3)
        (k (tarai-cps t1 t2 t3)))))))))))))))))))
(time (tarai-cps 10 5 0 (lambda (x) x)))

(define tarai-anf
  (lambda (x y z)
    (let ((G139 (<= x y)))
      (if G139
   y
       (let ((G140 (- x 1)))
  (let ((G141 (tarai-anf G140 y z)))
    (let ((G142 (- y 1)))
      (let ((G143 (tarai-anf G142 z x)))
        (let ((G144 (- z 1)))
   (let ((G145 (tarai-anf G144 x y)))
     (tarai-anf G141 G143 G145)))))))))))
(time (tarai-anf 10 5 0))

(define tarai-lambda
 (lambda (x y z)
  ((lambda (G143)
     (if G143
  y
  ((lambda (G144)
     ((lambda (G145)
        ((lambda (G146)
    ((lambda (G147)
       ((lambda (G148)
   ((lambda (G149)
      (tarai-lambda G145 G147 G149))
    (tarai-lambda G148 x y)))
        (- z 1)))
     (tarai-lambda G146 z x)))
  (- y 1)))
      (tarai-lambda G144 y z)))
   (- x 1))))
   (<= x y))))
(time (tarai-lambda 10 5 0))
tarai-orgが元のたらいまわし関数。以下、-cps、-anf、-lambdaと続くが、順に元の関数のお手製CPS変換、A正規化、A正規化後letをlambdaに変換したものとなっている。 っで、以下がベンチマーク結果
Petite Chez Scheme 7.9.4
(time (tarai-org 10 ...))
    no collections
    16 ms elapsed cpu time
    0 ms elapsed real time
    0 bytes allocated
(time (tarai-cps 10 ...))
    no collections
    0 ms elapsed cpu time
    0 ms elapsed real time
    840 bytes allocated
(time (tarai-anf 10 ...))
    7 collections
    78 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    29505472 bytes allocated, including 29469704 bytes reclaimed
(time (tarai-lambda 10 ...))
    7 collections
    78 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    29505120 bytes allocated, including 29489216 bytes reclaimed

Gauche 0.9
;(time (tarai-org 10 5 0))
; real   0.016
; user   0.016
; sys    0.000
;(time (tarai-cps 10 5 0 (lambda (x) x)))
; real   0.000
; user   0.000
; sys    0.000
;(time (tarai-anf 10 5 0))
; real   0.031
; user   0.031
; sys    0.000
;(time (tarai-lambda 10 5 0))
; real   0.437
; user   0.359
; sys    0.078
個人的には超意外にもCPSが一番早かった!!
Gaucheのdisasm関数でコンパイル結果を見てみたが、末尾最適化が効いてるのかな?
Chez Schemeの結果からアロケーションが結構発生するみたいだけど、それを踏まえてもありと思わせる結果である。

でも、これってこれらのVMがCPS変換されたコードを速く走らせるのであって、CPS変換されたコードが無条件で速くなるわけではないんだよなぁ・・・
う~ん・・・

2010-06-01

CPS変換

とりあえず基本的なことを勉強してみた。
とにかく、すべてのλ抽象は次に計算される継続を持てばいいみたいで、こんな感じに変換される。
(この辺は知っていた・・・つもり)
; 変換前
(define (pyth x y)
  (sqrt (+ (* x x) (* y y))))
; 変換後
(define (pyth x y k)
  (* x x (lambda (x2)
    (* y y (lambda (y2)
      (+ x2 y2 (lambda (x2py2)
          (sqrt x2py2 k))))))))
CPS変換するとこうなる。プログラムは継続渡しスタイルなので、「*」、「+」といったプリミティブでさえ、引数に継続を取る。
ということは、継続を取る引数を定義しないといけない・・・
こんな感じ。
(define (cps/* x y k) (k (* x y)))
(define (cps/+ x y k) (k (+ x y)))
(define (cps/sqrt x k) (k (sqrt x)))
上記のプログラムの*、+及びsqrtをCPSなプリミティブに置き換えれば動く。面倒・・・

っで、これ見ると分かるのだが、継続渡しのプログラムは戻り値を次の継続に渡すので必然的に渡される継続の引数は1つに固定される。
引数を一つに固定して、あだこだするというと、カリー化が思い浮かぶが、やらにゃならんのだろうか・・・

とりあえず、用事ができたのでここまで。続きは帰ってきてから。

-----------------
帰ってきた。

引数を一つに固定したくないという思いをいただいたので(誰からだよ!)
継続の戻り値が多値なら問題ないかと。とりあえず、実験。
(define (cps/+ k . arg)(k (apply + arg)))
(call-with-values (lambda () (values (lambda (k) k) 1 2 3)) cps/+)
call-with-valuesが内部で何してるのか実はよく分かっていないが、動きから第二引数に第一引数の戻り値をapplyしてるのではないかと・・・
まぁ、どうでもいいや。
こう書けば一応複数の引数を何とかできそうだが、いいのか?
とりあえず、最初のプログラムを手動CPS変換してみる。

と思ったが、CPS変換で生じたλ抽象って、この場合だと(* x y)の戻り値を引数にするのだから、1つ固定でも問題ない気がする。もちろん、 (values 1 2)見たいな多値を返すんだとしたら問題かもしれないが、Schemeは多値をそのままでは扱えないので、やっぱり問題ない気がする。

例みたいな、defineをCPS変換する際には関係ないのだろう、きっと・・・