Syntax highlighter

2012-04-17

hierarchy

Twitterでこんなことを呟いたら、突っ込まれたのでネタにする。

ネタを書く前にまず、僕の中でhierarchy(ヒエラルキー)という言葉のイメージを説明しておく必要がある。(これが長くなるのでブログにした)
僕の中でのhierarchy意味は、トップダウン型の階層である。これは恐らく日本語ではヒエラルキーなんて言葉を使っていなかったのと、プログラム関連から意味が入ったこと、またこっちではその意味でしか使わないことがあるだろう。例えばカーストのヒエラルキーとか、食物連鎖のヒエラルキーとかはまぁ意味が分かる。個人的には日本訳がある言葉をわざわざカタカナで書く必要はないだろうと思うのだが。インテリの考えることは分からん。

っで、美醜のヒエラルキーという言葉を何を見たときに意味が取れなかった。何のこと?考えて、階層転じてランクのことかなぁととりあえず流してTwitterで呟いたと。
まぁ、これだけでは1000見て1違うから意味が複数あるというのもおかしいなぁと思い、Google先生でヒエラルキーを調べてみた。関連ワードで既に意味の分からないもの発見したので、まぁ誤用も一般的なんだろう。
意味の分からなかったもの。
  • 幸福の科学ヒエラルキー
  • 天使ヒエラルキー
  • 顔面ヒエラルキー(※)
  • 公正価格ヒエラルキー
※ hierarchyにはもう一つ「構造」という意味もあるらしい(僕の中にはイメージとしてない)。顔面構造と訳せば意味は分かる。
顔面ヒエラルキーはGoogle検索の2、3ページあたりの検索結果で、あとは関連ワード。どれも階層と訳して意味が通じない、少なくとも僕の中では。構造だと、公正価格あたりはいけるかも。
最初に挙げた美醜に関してはどちらで訳しても意味が通じない。美醜というひどく抽象的な概念に対して、hierarchyというより具体的なものを指す単語を当てているのでイメージがまったくつかめないというのが理由だろう。訳語を当てても、「美醜の階層」もしくは「美醜の構造」となり意味不明である。(原文でどのように使われていたのか思い出せないので、ひょっとしたら前後のつながりでいけるのかもしれないが。)

そういえば、ダーリンの頭の中(母親が持っていた)にあった、テンションと似た感じかもしれない。英語ではテンションは「張る」ものだが、日本語では「上がる」ものだったりする。

どうでもいいのだが、ヒエラルキーという発音はどこから来たんだろう?ラテン語かな?英語だと、「ハイエラキー」に近いと思うのだが。

2012-04-16

Sagittarius 0.3.1リリース

そろそろ月1のリリースがきつくなってきた。そして、意味があるような気がしなくなってきた。

今回のリリースはメンテナンスリリースです。

修正された不具合
  • パターン変数がライブラリを超えられない不具合が修正されました。
  • define-library構文がcond-expandを認識しない不具合が修正されました。
  • "\x0;"が正しく読まれない不具合が修正されました。
  • bytevector-s64-(native-)-set!が#x-8000000000000000に対してエラーを投げる不具合が修正されました。
  • make-vectorにfill引数を与えなかった際に未定義値ではない値がセットされる不具合が修正されました。
改善点
  • 暗号ライブラリ及び数学ライブラリの一部が書き直されました。これによってユーザー定義のCipher及びハッシュ関数を既存のAPIで使用することが可能になりました。
  • ASN.1ライブラリが大幅に書き直されました。
  • define-class構文が:metaclassオプションを受け取ることができるようになりました。
新たなライブラリ
  • SRFI-4ライブラリ(srfi :4)が追加されました。
  • HMACライブラリ(rfc hmac)が追加されました。ただしMACの検証はできません。
  • PKCS#5及びPKCS#12ライブラリ(rsa pkcs :5)、(rsa pkcs :12)が追加されました。PKCS#12はドキュメント化されていません。
  • バイトベクタライブラリ(util bytevector)が追加されました。

Visual StudioでGDBっぽいWatch

WindbgではできなさそうなのでとりあえずVS2010ExpressEditionで。
以下のサイトを参考に。
指定のアドレスのメモリが変化したらブレークするブレークポイントを作成する - メモブロ 

Data break pointという言葉が分かればGoogle先生に伺いやすい。ということで伺ってみたら、Windbgにもあった。GUIから設定できるかまでは探していないが、baコマンドでいけるっぽい。

とりあえず、分かったこと。
やっぱり語回収されているっぽい。メモリを書き換えているのはGCのreclameという関数だった。Cygwinと同じようなことをしないと駄目なんだろう。どうやればいいんだろう?

2012-04-15

Meetup

Trying to be active.

と称してLeidenのシーボルト博物館meetupに行ってみた。Salon - Japanese Talk in Amsterdamというmeetupなのだけど、なぜかアムスではなくライデン。単にたまには日本語を喋りたいと思ったのが参加した主な理由だが、当てが外れた。日本人僕一人、あとはフランス人とスペイン人(発案者は何人だろう?オランダ人っぽくなかったなぁ)。話した日本語0、あれ?

特に収穫というものもなく、切ない思いをした。

ここからも、どうでもいい話:

フランス人(特にパリ辺り)では日本の文化を学びたい人が多いらしい。その理由は、テレビでは日本のアニメが流れ、ゲームは日本の物が流行り(何かは知らない。FFとかテイルズかと)、漫画は言うまでもないという状態だから。つまり、オタクであるほど日本に興味を持つっぽい。話の中で出てきたアニメと漫画がすべて分かった自分もそっち方面だと自覚してるさ・・・今まで聞いた日本のイメージって、オタクかロボットしかないんだけどどういうことだろう?

オランダにはいわゆるカルチャースクールみたいなものが少ないらしい。そこにいた人の意見ではオランダ人は特に趣味が無く、エロ話してバーでビール飲めたらいいじゃんってイメージらしい。概ね同感だが・・・

フランス人は週に35時間しか働かなくてもいい上に休暇もたくさんあるというのは単なる伝説らしい。公務員はそうだけど、普通の企業の人は普通らしい。(まぁ、それでもヨーロッパ基準の普通なので日本に比べればはるかにましだろう)。

2012-04-14

君をつれて

2002年にDVD化された天空の城ラピュタの16年後のパズーの心境を石井竜也が歌ったとされるもの。ちなみに、天空の城ラピュタは数少ない何時見ても感動できる作品に一つだと思っている。(竜の巣へ入る際のデジタルリマスタリングは正直邪魔だと思っているが・・・)

話が逸れた。物語の中でパズーとシータの年齢は明かされていないが、恐らく14、15歳くらいだと思う。その16年後なので、30歳くらいのパズーを歌った歌ということになる。ただ追い求めるだけの少年から守るものが出来、それでも君と一緒にまた旅に出たいという大人の視点な歌詞だと思う。(国語苦手・・・)
歌が作られたのは今から10年前だけど、僕の年齢がちょうど歌の歌詞とマッチするなぁと思って書いていたりする。すごく分かるなぁというのが感想なのだが、それと同時に大人になるということは夢を見ているだけでの少年ではいられなくなるということなんだなぁと実感した。無数にある可能性という枝の中で望むと望まざると選択せざるを得ず、現実という名の下に刈り取られた無数の夢、それらを受け入れてなおまた旅に出たいあの頃のように。なんて感じたのはまぁ、きっと自分の中にそんなことを考えている部分があるのだろう。

希望に満ちた天を突かんばかりの摩天楼の群れだったこの世界は、お前の身近にあった小さな街の風景になりさがった。From Bleach(あってる?)

最終的には何になるんだろう。今は住んでるアパートかね。脱出ゲームばりに。

2012-04-13

Windowsをサポートするということ

割と茨の道だと思えてきた。

何が起きたか。
多分GC関連の不具合。以前Cygwinで似たようなことが起きたので。

なにそれ?
動的にリンクされるモジュール内で割り当てられたメモリが誤回収されているっぽい(値が勝手に書き換わっている)。
 Cygwinではルートを追加してやることで回避したんだけど、Windowsではどうやってやるんだろう?最新版のGCでは解決されているのだろうか?(それにしても、7.2-Alpha6からちっとも次が出ないなぁ)

そもそもほとんどダウンロードされていないプログラムなんだから別にサポートする必要ないじゃんとか思っていたのだが、自分がWindows版を普通に使っている現実があってごにょごにょ・・・

2012-04-10

Memo: Cache reader improvement

Since Sagittarius supports SRFI-4 (well, it's not released yet), the cache reading problem is totally floated up.

Before I describe the problem, I need to write how exactly the cache mechanism works. The reason why Sagittarius has cache is because of performance improvement. Let's say when (rnrs) library is loaded, then related libraries are also loaded (of course). However Sagittarius does not have compiled base library like Ypsilon and mosh have. So each time these library are loaded, compiler is also invoked. This caused really bad performance problem. So I introduced the cache mechanism.
However it is not completely done and I was searching what is the better solution for it. Right now, when Sagittarius load a library, it tries to find the cache first and if it can not find then compile the real library and write its cache.
Then what if there is a non cachable object in the compiled code. Yes, this is the problem. You can simply try how to make invalid cache code. Write a reader macro and let it return a hashtable (yes,  even hashtable can not be cached.) Current implementation has no space to expand the behaviour.

What I am thinking is adding two slots to base classes like 'readCache' and 'writeCache'. It is possible since Sagittarius has supported CLOS. Then introduce <fasl> class to allow user to write own cache reader. I am planing to implement this in 0.3.2 but I'm not sure if I can...

2012-04-09

チラシの裏

そもそもこのブログ自体がチラシの裏なので更に裏返したら表になってしまう(わけない)。

単にどこかに吐き出さないと精神衛生上よろしくないなぁというだけで別に誰かに読んでほしいとかそんな意図はさらさらない話題。

2月くらいに元彼女と別れたのだが(まぁ去年の12月くらいから関係は最悪だったが・・・)、まぁいろいろ物が残っていたり宅配が未だにこっちに来たりとなんだかんだで顔を合わせる機会が多い。そのたびにものすごいストレスが掛かる。別に話すことは何もないし、向こうもこちらも何かを何かをするわけではないのだが、扉が開く音を聞くだけで体が硬直する感じ。
理由はまぁいろいろあるんだけど、散々人格否定されてダメ人間の烙印押されたものだから勝手に体が防戦体制に入るんだろうね。正直ここから逃げ出したい気分に1ヶ月の80%くらいはなっていたりする。もうなんかうっかり街中で遭遇するんじゃないかっていうのすら心配になる。

年収600万以上+残業代その他別支給な仕事ないだろうか・・・日本に帰ってもいいかなぁと本気で考えていたりする・・・

しかし、アレだけ人を罵っておいてしれっとした態度が出来るっていうのは一体どんな精神構造してるんだろうね。 正直、嫌悪感丸出しで目も合わせたくないみたいな感じの方が100倍気が楽だ。こっちも単に敵としてみればいいだけなんだし。

2e paasdag

標題はオランダ語。意味は2nd Easter day。

今日はイースターの二日目。正直イースターがなんだか分かってはいないのだが(キリスト教の何かだということは知っている)、オランダでは今日は休日になる。
だから何ということはないのだが、何をしていいのか分からないくらい暇。PKCS#12周りのコードは会社に全部置いてあるので何もできない。(仕事でP12ファイルの中身確認に使っているので。ついでに、P12ファイルなんて手元にない)。

天気も悪いし、どうしたものかね・・・

2012-04-06

R7RSの第5次投票

月刊R7RS - 第五次投票の結果が出る - .mjtの日記復帰計画を見て出たんだとチェック。

正直R7RSサポートと称してドラフト5対応にしたのは時期尚早だったなぁと激しく反省した。所詮はドラフト、いくつ出ようが大きく変わるものだ・・・
大き目な変更点(Cレベルで変更が必要なもの):
  • ベクタがセルクオートになった。
  • シンボルのエスケープが変わった。\x..;は中で見る必要がなくなった。
ライブラリとかプロシージャの変更は特にいいか。ドラフト5でほぼ決まって6くらいで固まるかと思っていたのだが、見通しが甘すぎたね。本決まりまで静観した方がいいかもしれない。

SRFI-4 has been supported

I have wrote a library which supports SRFI-4. This might be the very first library using reader macro from Scheme. (I don't remember if I have already written something before). Well, actually R6RS already has bytevector to handle these homogeneous numeric vectors, however it is sometimes convenient if I can write #s8(-128 127 ...) instead of #vu8(255 127 ...). So now, I can write like this.
#<(srfi :4)>        ;; enable the reader macro
(import (rnrs) (srfi :4))
(define s8 #s8(-128 127)) ;; #s8(...) is reader macro 
(display s8) (newline)    ;; prints #s8(-128 127)
(s8vector-set! s8 0 1)    ;; unspecified
(s8vector-ref s8 0)       ;; returns 1
(s8vector-set! s8 0 -128) ;; unspecified
(s8vector->list s8)    ;; (-128 127)
(list->s8vector '(1 2));; #s8(1 2)
(bytevector? s8)          ;; #f
The homogeneous vectors are not bytevector defined in R6RS. So bytevector? returns #f. Maybe I will write a conversion procedure someday.

The reason why I wanted this is really simple. When I want to read a byte array dumped from Java, it is convenient to be able to write it. (Well, if I dump it, I can convert it to unsigned. But if I peek it from debugger, byte in Java is signed. I really hate this). I actually didn't have any intention to make it a library but when I wrote the reader macro, I thought I will write this again if I don't make the library.

Why is it #s8 instead of #vs8?
Implementation restriction... #vs8 was too long for dispatch macro and if I did it, I also need to rewrite existed bytevector reader.

2012-04-03

PBEのCipher

いまいち上手くいかない。HMAC、派生鍵は動いているので後はここだけなのだが・・・

上記の2つが動いているのでナイーブな(正しくない)実装は動いているように見える。パスワードを与えて暗号化、複合化は出来ているということだ。
では何が問題か。同一のアルゴリズム、鍵、パラメータを使用した場合、JCEだろうが何だろうが同一の暗号結果を返さなければならない、という部分。俺々仕様ではダメなのが辛い。
一応BouncyCastleの実装も見てみたんだけど、恐らく初期ベクタの与え方が拙いと思われる。 ただ、実装を見た感じ、ブロックサイズのバイトを0で初期化しただけにしか見えないんだけどなぁ・・・派生鍵の部分で見落としがあるだろうか?回転数が違ってるとか。さすがにDESのCBCモードを自前で実装する気にはなれないのでどうしたものだろう。
どこかにPBEWithMD5DES辺りのサンプル(もしくは内部で何してるかの解説、仕様書)ないかな・・・
(ひょっとしてこれだとHMAC要らないってことないよね?・・・)

2012-03-31

死刑廃止論

Twitterでリツイートされていた記事を読んで感じたこと。
元記事はこれ:「自分の子どもが殺されても 同じことが言えるのか」と 書いた人に訊きたい

多少批判的なことをを書くので、その前に自分の立場を明確にしておこうと思う。僕は死刑賛成論者である。理由は「凶悪犯罪を犯したものの再犯率を考えれば死刑にした方がよい」というもの。性悪説支持とも言えるか?そもそも、日本で死刑を求刑されるほどの犯罪ってかなりの凶悪犯罪だった気がする(うろ覚え)。なので、同規模の犯罪を再犯されるよりは、そいつの命1つ奪っておいた方が社会的に利益が大きいだろうというもの。別に人は更生できないと言っているつもりはない。また、上記の記事にあったような「被害者家族のことを考えろ」というものではない。

この記事を読んでまず思ったのはちょっとコメントを恣意的に拾いすぎだろうというもの。僕は勝間和代という人がどんな人か知らない。ひょっとしたらいわゆるプロ市民、極左な人であまり世間でいい評判が無いために何を言っても批判、罵倒を浴びる人なのかもしれない。また、その動画を見ていないので本当にそんな意見ばかりが流れたのかも知らない。
最後まで記事を読んだ後に感じたのは、「著者は単に死刑賛成論者を批判したかっただけではないか」というもの。確かに言っていることは正論だし、まぁ筋も通っているなぁと思ったんだけど、問題なのは「自分がどちらの立場かを明確にしていない」ということ。ひょっとしたら冒頭の部分で反対論者であると言っているのかもしれないが、もしそうなら言い回しは非常に分かりにくく、あえてぼかしているように見える。しかも、最後に自分が当事者になったらスタンダードは変わるなんて言っている辺り、自分に降りかかる批判を避けているだけにしか見えない。
少なくともコメントを残した人は自分の主張をしているので、議論をするのであれば立場を明確にしないと話にならないのではないか?(あぁ、だから著者は反対論者で自分が当事者になったら賛成論者になると明言しているのか)

国語の成績は悪かったのでこの著者が「本当に言いたいこと」というのが読み取れていない可能性が高いが、理路整然(ともしていないが)と頭ごなしにコメントを残した人を非難しているように見えたので、なんとなく噛み付いてみた。
議論すべき問題だとは思うけど、この記事は持ってく方向がおかしい。 (そもそも議論ではないのか)

2012-03-27

署名と検証

Pure JavaScriptでRSA署名するソースを公開しちゃいますよ~~~~w
なんてのを見つけて、こりゃ手軽にSagittariusの(crypto)ライブラリ(というかRSAか)が上手く動いているか楽に検証できるや、と試してみた。

結論を言えば、上手く動いていそうなのだが、ちょっと戸惑った。(最初にX.509の証明書から公開鍵を引っ張り出す作業が必要だったが、まぁこれはいいか)
最初に試したのはデフォルトの挙動。これが戸惑った部分で、署名が毎回違う値になる。でも検証すると毎回OKがでる。上記のサイトは同一メッセージなら毎回同一の署名。
正直一瞬バグを疑ったが、よく考えてみると署名と検証で使うエンコーダとデコーダが指定できる作りになっているのを思い出した。っで、デフォルトだとPKCS #1 EMSA-PSS-ENCODEを使っていて、こいつはsalt入れて毎回違う値を吐き出すようになっている。(まぁ、その方が安全だしね)
っで、もう一つ実装してある、 PKCS v1.5 エンコーダを試してみたらまったく上記サイトと同じ値になった。どうやらよさげ。

っで、気になるのはx.509との兼ね合いを考えた際にどっちがいいんだろう?というもの。多分そのうちx.509の証明書を読み込めるようにするので、デフォルトでとりあえずx.509の方式にしておきたいなぁと。RFC読めということかな・・・

RFC2898(PKCS#5)斜め読み

斜め読みもしてないな、眺めただけか・・・

何が知りたかったかといえば、PBEが意味するところと、PKCS#5自体が暗号化のアルゴリズムを規定しないということ。実際そうだった。
では何を定義しているのかと言えば、(眺めただけなので違うかもしれないが)もう一つ上の層というか、より安全に暗号化する方法みたいなものと、とりあえずこいつに従っておけば中身は違っても表面上は何をしているかが統一できるといった感じのもの(だと思う)。
たとえば、派生鍵の作成手順とかその鍵を使った暗号化とかそんなの。でも派生鍵を作成する関数(KDF, Key Derivation Function)は外から渡す必要があるし、暗号化そのものを行う関数や、ハッシュ関数も外から渡す必要がある。 (もちろんMAC関数も)
嘘。KDFに関してはPBKDF1とPBKDF2がどういった関数であるけPKCS#5(RFC2898)内で定義されてた。MACも書いてある。さすがにハッシュ関数は別物だけど。

そうは言っても渡された関数に渡すパラメータとか統一できんよというために、関数が受け取るパラメータも定義してあって、その中にどのアルゴリズムを使うかを指定できるようになっている。まぁOIDでなわけだが。

問題にするところとしては、(crypto)ライブラリを書き直すもしくはてこ入れをするとして、このPKCS#5的に直すのか、とりあえずこういったものも実装しやすいように直すのかで大分方針が変わる気がする。後者かな。PKCS#5をサポートしたかったら(rfc pkcs :5)とか(pkcs :5)とか提供すればいいわけだし。ただ、派生鍵をどうするかは考えないと。こいつばっかりはアルゴリズムにどうしても依存するわけだし。(しないのか?調べないとなぁ)

どうでもいいけど、暗号関連の何かを読むと必ず「salt」って出てくるけど、塩って訳すと変だよなぁ。なんて訳すんだろう?

2012-03-26

(crypto)ライブラリを見直したい

願望形・・・

何が問題かと言えば現状ではサポートしていないアルゴリズムはまったく扱えないということ。追加もできない。別にそれでいいじゃんと言えばそうなんだけど、せっかく抽象化しているのにサポートしてないものはべた書きでは面白くない。
ということで、APIを見ながら何がどうなればいいかということを考えてみることにする。
cipher
アルゴリズムをラップしたCipherオブジェクトを返す。現状では与えられたCipherタイプが定義済みの共通鍵方式かどうかを判別している。(まずはこれか)
encrypt
decrypt
Cで書かれたsubr。中身はやっぱり共通鍵かどうか見てディスパッチしてる
signature
verify
Cで書かれたsubr。共通鍵ならエラーは上げる。Schemeで書かれたsignerとverifierを呼び出している。
他にもcipher-keysizeとかあるけど、とりあえずはいいだろう。後はモードとサポート済みアルゴリズムだし。generate-secret-keyとかも考える必要はあるだろうが、とりあえずいいか。
(しかし、結構でかいライブラリの割りに、口は少ないなぁ。いいことなのか?)

っで、どうしたいか。今回まずいなぁと思ったのは、PKCS#12のファイルを読み込む際にPBEが複号できないといけないのだが、(crypto)ライブラリではサポートされていない上にcipherを作ることも追加することもできない。 これはよろしくない。(元々はlibtomcryptの薄いラッパーのつもりだったし十分ではあったのだが)
とりあえず案としては、pimplみたいな感じで<cipher>と<cipher-spi>(名前はJCEから)クラスを作って、標準サポートに<builtin-cipher-spi>、ユーザーが追加したかったら<cipher-spi>を継承したクラスを作るという風にしたらいいだろうか。ちょっと考え方がJavaよりで、関数型ではないかもしれんが・・・

2012-03-24

The catcher in the rye

多分このタイトルどこかにあると思うが。

街まで出る必要があったのと、さらに時間を潰す必要があったのでポケットに入るサイズの本を探したらこれかアリスしかなかっただけだが。
時間つぶしのためスタバ(オランダにもあるんですよ)に入ってコーヒーとアップルパイを貪りながら読んでた際にある一文が目に入ってすごく共感したなぁという話。 以下がその一文。

The catcher in the rye, chapter 2.
"I'd like to put some sense in that head of yours, boy. I'm trying to help you. I'm trying to help you, if I can."
He really was, too. You could see that. But it was just that we were too much opposite side of the pole, that's all.
最後の文がそれなんだけど、最初のSpencer先生の行からじゃないと意味不明なのでそこから引用。この前の部分で先生がHolden君に対して何でこんな解答をテストでしたんだみたいなのがあって、落第していくHolden君をなんとか救おうみたいな流れ。
昔読んだときは正直それを突っぱねるHolden君に共感できなかったんだけど、今なら分かる部分がある。Spencer先生は最初に傷口に塩を塗りつけて、ほら君はこんなことをしたんだよ、なんでやったんだい?みたいに聞いていて、そりゃあ意固地にもなるわなぁと。実際自分もこれと似たようなことを何度も何度もやられたので。
ここで大人な対応でいろいろ受け入れられればいいんだろうけどそれが出来る人間ってどれくらいいるんだろう?
例えば仕事とかで何かミスを犯す度に上司から3年くらい前のことまでひっくり返されてネチネチ言われた挙句、「俺はお前を助けてやってるんだぞ」みたいなことを言われてさてどれくらい信じられるかと。
それでも仕事なら給料のためとか割り切れるけど、僕の場合はこれが人間関係だったので心が折れた。

久しぶりに読んだ本で昔は共感できなかった青臭い部分に共感している辺り、精神年齢が下がっているのだろう。もしくは大人になれてないか。

2012-03-23

マルチスレッドテスト(結果)

連投だなぁ、まぁいいか。
多少の制約があるものの、まぁ元気に動いている感じ。っで、せっかくマルチに走らせているのだから、どれくらいパフォーマンスに影響が出たかというところが気になる。っで調べてみた。

実行環境: Cygwin on Windows 7 (64bits), Core i7
シングルスレッド
% time sash run-test.scm sitelib
;; ログ省略
sash run-test.scm sitelib  3.99s user 0.25s system 99% cpu 4.243 total
マルチスレッド
% time sash run-test.scm sitelib
;; ログ省略
sash run-test.scm sitelib  4.79s user 0.25s system 252% cpu 1.997 total
※ 実行スクリプト内を直接いじっているので、コマンドは一緒に見えるけど、中身は違う。

2倍速!CPUの使用量が200%を超えとる。やった甲斐ありと思っていいかな。

マルチスレッドテスト(依存関係問題)

昨日の変更で一度作成されたライブラリはグローバルに持つようにしたので、キャッシュを読み込むときに問題が起きるようになった。
問題としては(恐らくだが)、スレッドAがライブラリhogeをキャッシュから読み込んでいるときにスレッドBも同じライブラリを読み込むとどうなるかというもの。 現状だとキャッシュの読み込みには特にロックを取得していないので、データ読込→ライブラリ作成→データ復元→インポートという流れの中で問題が起きるのかなぁと(確証ない、状況証拠のみ)。

上記の仮定が正しいとして、解決方法を少し考えてみた。
  1. キャッシュ読み込み時に、プロセスリストを作成し、そのリストの中に自分が必要としているキャッシュがあれば待つ。
    でもこの場合同じライブラリだけど別ファイルだったらどうなるんだ?
  2. キャッシュ読み込み自体にロックをかけて、ライブラリが存在しているか確認、あれば帰る
1の場合は同一ライブラリ別ファイルの対処が多分不可能。2の場合はせっかくマルチに走らせるのにキャッシュの読み込みがボトルネックになる。実装としては2の方が楽。
マルチスレッドでloadを使うなんて事がそうあるとは思えないので、とりあえず2を実装してみればいいだろうか?

2012-03-22

マルチスレッドテスト(調査)

テストケースをファイルをロードしてテストするという風に変更したのだが、スレッド作って可能な限り同時に流した方が効率がいいよなぁと思い簡単なテストをしたらこけた。
っで調査。

問題になるのは、共有オブジェクト(DLL、so)で作られたライブラリを読み込むテスト。(意外な依存関係があったりするので、ピュアスキームだけマルチでって分けにはいかないのが辛い)。
なぜかその類のライブラリがあるとインポートエラーになる。ちょっと実装を覗いた。共有オブジェクトは一度呼ばれるとその情報が保存されて、同じオブジェクトを2度読み込まないようになっている。まぁこれはいい。っで、その中に初期化関数があるのだが、読み込みの際にそいつも一緒に呼ばれる。そうするとオブジェクトは初期化されたというフラグが立つ。ここに問題があった。

親スレッドが呼ぶ分にはまったく問題ないんだけど、複数の子スレッドで同一のDLLが呼ばれると問題になる。
この辺は多少以上に設計方針に関わっていて、子スレッドでインポートされたライブラリは親スレッドに影響を与えないという作りにしてあるのだが、これが拙い。兄弟間ではライブラリの共有が出来ないからだ。そうすると一度呼ばれたライブラリは2度と初期かされないので、兄が呼ぶと、弟が呼んでも答えてくれない。
解決策はまぁ、2つだろう。子供は親に迷惑をかけるものだと割り切るか、ターゲットを八方美人にするか。設計方針的には後者になるか。ただ、実際2度初期化をするとおかしくなるものもあるので、そこは気をつけないとまずいか。

2012-03-21

Weak hashtable

マクロ周りの修正と、デバッグ情報(主にファイル周りの情報)を何とかしようとしたらメモリがあっという間に飛ぶようになったので、ちょっとまじめに実装しようとしてみた。

問題になったのは、VM側にソースの情報を持たせているのだが、こいつが普通のハッシュテーブルなので要素は増えるけど減らないというのがある。たとえばユニットテストなんか走らせると最低でも500MBぐらい必要だった。

元もと使ってはいなかったがWeakハッシュテーブル自体はコードにあって(Gaucheからのパクリ)、単にこれを使えばいいかなぁと思っていたのだがそう単純な話でもなかった。

何が問題だったか。
GaucheのWeakハッシュテーブルはキー、値、もしくは両方という感じでどの要素がWeakポインタなのか指定できる。しかし、そのままの状態でうまく動いたのは値を指定した場合のみで、キーまたは両方を指定すると値が取り出せないか最悪クラッシュする。(最新版のソースは知らない+Gauche上で使ったことないのでその辺は考慮されているのかもしれない)

どうしてそれが起きたのか。
Weakハッシュテーブルに要素を入れるとき、GCが辿らないように要素を一段ラップするようになっている。問題はここで、値だけなら問題ないが、キーをラップしたときラップされたポインタは闇に消えていた。なので、値を取り出そうとすると必ず失敗する。(だって、キー自体とラッパーは違うんだもん)

ではどうしたか。
非常に醜い方法でとりあえず回避。ハッシュテーブル自体にラップされたキーの情報を持たせるようにした。値を入れる際にキーの情報も一緒に保存しておく。っで、取り出す際には保存先から生のキーを元にラップされたキーを取り出す。ただ、これ自体がGCから辿れると結局回収されないので、これ自体もWeakベクタで実装。ただ、キーの情報が増えるとベクタが爆発的に増えるのでパフォーマンスに影響がでる。(というか出てる)。

最終的にはメモリ使用量が最大で200MBくらいに落ち着いたので、まぁよしとしている(これ以外にもいろいろやっているが)。キャッシュされてしまえばソース情報は消えるわけで、コンパイルもスキップされるから速度的には問題なくなると思うし。

2012-03-19

なんとなく

自分のブログの過去ログを眺めていた。2006年からこのブログ書いてるんだとちょっと感心。
最初の頃はPerl、C++にくびったけだったのが分かる。あと文章が幼いw(今も幼いが・・・)
FTPの実装方法が分からないなんていってる自分がいるのを見ると、技術的なスキルや知識はついたんだなぁと思う。(まぁ、Socket周りなんて仕事ではなくSagittariusの開発からだけど)
2009年からはこっちにいるのだが、その頃辺りからSICPとかSchemeの話題が出てくる。でもその前から言語の処理系を作りたいみたいな文章があって、その辺は変わってなんだなぁと実感。

結構いろんな箇所で自分は感情が欠落しているというのを誇張しているが、まぁ軽い厨二病をこじらせていたのだろう。まぁ、今では立派な甲斐性なしにレベルアップしたけど。

短い文が多いのは当時はブログに何を書いてもいいだろうと思っていたんだろう、どうせ人は見ないしと考えて。(今でも需要があるとは思わないが)。

読んでもその当時自分が何をしていたのかってのがいまいち思い出せない。けど、いろんな意味で自分は変わったんだなぁと実感した。本質は変わってないんだけど、枝葉というか、まだ若くて何も知らなかった自分(25、6なのに)というのから、人の目を気にして、評価を気にして、大切なものが何なのか分からなくなった自分という感じではあるが。(じゃあ、僕の本質って?多分あほなんでしょう。または考えなしか)

自分がしたことに後悔がないと言えば嘘になるし、可能であれば取り返したいという気持ちもあるけど、後ろを見てもしょうがないよねというのが一番強いではある。覆水盆に返らず、僕だけが水を溢したわけではないと思うけど、一度失ったものは帰ってこない。この国で独りで生きるのはまぁ辛いだろうが、なんとかなるだろう。 退かぬ、媚びぬ、省みぬ!(だっけ?)

promiseとfuture

C++11から入った機能。JavaのFutureとよく似てる?

まぁ、C++で使うことはないのでSagittariusですごくナイーブに実装してみた。ひょっとしたら使うようになるかもしれないというだけで。
(import (rnrs) (srfi :18) (clos user))

(define-class <promise> ()
  ((future :init-keyword :future)
   (thread :init-keyword :thread :accessor promise-thread)))

(define-class <future> ()
  ((promise :accessor future-promise)))

(define (make-promise proc . args)
  (let* ((thunk (lambda () (apply proc args)))
  (thread (make-thread thunk))
  (future (make <future> :thunk thunk))
  (promise (make <promise> :future future :thread thread)))
    (future-promise future promise)
    (thread-start! thread)
    promise))

(define-method get-future ((p <promise>))
  (slot-ref p 'future))

(define-method get ((f <future>))
  (let ((promise (future-promise f)))
    (thread-join! (promise-thread promise))))

(let* ((promise (make-promise (lambda args
    (thread-sleep! 1000) ;; heavy routine
    (apply + args)) 1 2 3 4))
       (future (get-future promise)))
  ;; do something 
  (print 'here)
  ;; wait
  (print "get value " (get future)))
こんな感じ?あんまり何も考えてない。値の取得が2回起きたらどうなるとか。なんかこの程度だとスレッドの薄いラッパーにしか見えないなぁ。どうするのが正しいんだ?

2012-03-18

WATCOMとGCCの違いメモ

結構違いがあってびびった。まだコンパイルが通るだけでまだまともに動かないが・・・
あと、WATCOMのターゲットはWindowsなので、UNIX関連はまた別になるけど
voidの関数が値を返すようなreturnをするとコンパイルエラー
これはGCCやMSVCが甘すぎるのだと思う。正直こうあってほしい。
small、medium、large、hugeがマクロとして定義されてる
Linux版GCCのgetcとかputcのマクロ並に邪悪です。速攻undef。
構造体の初期化で使えるのは定数のみ
結構使っている箇所があった。正直許せよこれくらいと思った。
NaNが0より大きい
これははまった。数字じゃないのに、そんなの返すなよ。多分コンパイラのバグ(と思う)。
左シフトで桁あふれすると0になる
Cの規格では未定義動作なのでコンパイラの警告を無視していた僕が悪いのだが。
静的領域や大域変数は4バイト境界に配置
8バイトを期待したコードを書いていると困る。doubleを噛ませても問答無用だった。__farキーワードで回避
exp、log、powが微妙
まだ原因を特定してないけど、上記の数学関数がOverflowやらRange errorやらDomain errorを投げる。GCCとMSVCは投げない。多分シフトの桁あふれと関連してるのだろう。中身があんまり賢くないようだ。
externされている大域変数の参照が不正
__farキーワードのせいなのか、LoadLibraryの問題なのかは分からない。後者はWin32 APIだからちょっと考え難いか。前者かな?リンカーという線もあるが。
modfにINFINITYを渡すとNaNを返す
GCCとMSVCは0を返す。
根本的にNaNの扱いがおかしい
NAN==0.0が真になるとかありえないだろう。他にもいろいろ偽を返すべきところで真を返す。
logに-INFINITYを渡すとDomain error
だけならいいんだけど、そのまま-inf.0を返しやがる。+nan.0を期待しているのだが・・・
エクスポートされる関数の名前がおかしい
普通は_nameなんだけど、name_と逆になる。dllexportがおかしい?。__cdeclをつける必要あり。
最後のが特定できてないのでR6RSのテストケースが通らない。通した。modfのNaN問題だった。
また、動的モジュールのロードがおかしいのか分からないけど、拡張モジュールがまったくテストできない。
あまりメジャーな処理系ではないらしく、資料もそんなにないし、マニュアルでは痒いところに手が届かない(8バイト境界とか)。2日で何とかなるとは思っていなかったが、想像以上に癖がありすぎて挫折しそう。
とりあえずブランチ切ってコミット。他の処理系で問題なく動くならマージしようかな。とりあえず入れておけば誰か(一人プロジェクトなのに?)が突っ込みいれてくれるかもしれない。

2012-03-17

Watcomにはまる

自宅のThinkPad X60+Cygwinの環境にちょっと疲れてきたので(遅い、不安定等)、Windows上で使える第3の選択肢としてWatcomでビルドできないか試行錯誤中。っで、ちょっとした問題が発生した。
VC、GCCともにメモリのアライメントが8ビット(バイト?)境界なんだけど、Watcomは4ビットだった。これ実は大問題で、いろいろ8ビット境界を想定して書いているので思わぬところでこける。
オプションで指定できるのは構造体のアライメントだけっぽいし、staticな値を8ビット境界に置くにはどうしたらいいんだろう?ダメなら諦めるしかないが・・・

2012-03-16

クロージャー?

Twitterで呟いたが、Javaの無名クラスは厳密にはクロージャーになりえず、JDK8辺りで入る予定のlambdaも無名クラスの糖衣構文になるとかという話を昨日バーで同僚としていた。
糖衣構文でもあれば便利だろうなぁと思う場面が山ほどあるので、是非早いとこ実装してもらいたいが(JDK7では見送られた)。
話に参加していたもう一人の同僚が、違いが分からないと言っていたので、関数型言語のクロージャーとどう違うのかというのでも書いてみようかなぁと。ただ、僕自身あんまり理解してないので間違いは山ほどあるかと・・・

そもそも、クロージャーとは何ぞやと。詳しい説明はWikipediaでも見てもらうとして、上記で議論になっていたのは捕捉時の環境が閉じているかどうかということであった。JavaやC++ではここが完全に閉じることができず、渡された自由変数が参照渡しになる。以下はJavaでそれっぽく見せるようにしたコード。(C++では補足さえ出来ない)
package closure;

public interface Lambda<T> {

 T apply(Object... args);
}

// 別ファイル
package closure;

public class Closure {

 private Object obj;
 
 public void run() {
  // property
  Lambda<Object> lam = new Lambda<Object>() {
   @Override
   public Object apply(Object... args) {
    obj = args[0];
    System.out.println(obj);
    return obj;
   }
  };
  final Object obj2 = (Object)"string";
  Lambda<Object> lam2 = new Lambda<Object>() {
   @Override
   public Object apply(Object... args) {
    // obj2 = args[0]; // *1 compile error
    System.out.println(obj2);
    return null;
   }
  };
  System.out.println(lam.apply("here we go"));
  System.out.println(obj);
  lam2.apply();
 }
 
 public static void main(String[] args) {
  Closure cl = new Closure();
  cl.run();
  
 } 
}
*1の部分が重要で、Javaでは無名クラスの中から参照できる自由変数(とここでは呼ぶ)は変更不可能でなければならない。多分JVMの実装上も問題だろう。lam2がrunから戻った際にスタックからobj2が消えるのでその辺が問題になると思われる。
ではわれらがSchemeではどうだろうか?
(define obj #f)

(define (runner lam1 lam2)
  (print (lam1 "here we go"))
  (print (lam2 "we can do it")))

(define (main args)
  (let* ((obj2 "string")
  (lam1 (lambda (o) (set! obj o) o))
  (lam2 (lambda (o) (set! obj2 o) o)))
    (runner lam1 lam2)
    (print obj #\: obj2)))
#|
here we go
we can do it
here we go:we can do it
|#
あまりいい例ではない気もするが、lam2で捕捉されたobj2の値が変更されるとlambdaの外側のでも問題なく変更されている。
これが出来て何が嬉しいかと言われると正直微妙ではある。(結構使うけどこういうの)
ただ、Javaでもfinalつければ捕捉出来るんだし、ほぼ同じじゃないのだろうか?(いい加減)
(define obj #f)

(define (runner o run?)
  (let* ((obj2 o)
  (lam1 (lambda (o) (set! obj o) o))
  (lam2 (lambda (o) (set! obj2 o) o)))
    (cond (run?
    (print (lam1 "here we go"))
    (print (lam2 "we can do it"))
    (print obj #\: obj2))
   (else
    (values lam1 lam2 obj2)))))

(define (main args)
  (let ((o "string"))
    (runner o #t)
    (receive (lam1 lam2 obj2) (runner o #f)
      (print (lam1 "here we go"))
      (print (lam2 "we can do it"))
      (print obj #\: obj2))
    (print o)))
#|
here we go
we can do it
here we go:we can do it
here we go
we can do it
here we go:string
string
|#
こっちの方が捕捉時の環境というのが捕らえやすいだろうか?あんまり変わらないか?

2012-03-13

British or American English?

カナダにいたときに購読し始めたニュースレター(今はほとんど読んでなかった)から届いた面白げなタイトル。
その中にあった動画の一つがこれ
簡単な英語と米語の語彙の違いを紹介している。違いは以下のような感じ
BritishAmerican
TrousersPants
PantsUnderwear
視ると面白い。MeanがずっとBritishの方しか知らなかったり(Being Nastyなんて知らなんだ)。意外と米語だと思っていたのが実は英語だったとか(GardenとYardとか。スコットランドヤードって言うやん!)
自分の語彙を見ると主に日本で習う英語は米語だと思うが、たまに変なのもある(Trousersとか、学校ではこれがズボンと習ったなぁ。でも下着はUnderwearだった気がする)
謳い文句には文法も書いてあったのにサイトにそれらしいものは特に無かった。残念。

昨日の続き

意外とてこずっている。(まぁ、当たり前か・・・)
syntax-caseの実装が甘いのがここにきて痛い感じだ。
たとえばこんなコード。
(define-syntax print
  (syntax-rules ()
    ((_ o)
     (begin (display o) (newline)))))
(print
  (let ((x 'outer))
    (let-syntax ((m (syntax-rules () ((m) x))))
      (let ((x 'inner)) (m)))))
xという変数は合計で3回出現しているが、printマクロを噛ませることですべて同じ識別子へと見事な変貌を遂げている。これが問題なのだ・・・
syntax-rules内のxが3回目のxと同じため出力としてはinnerが帰ってくる。でも、printマクロを噛ませないとouterが帰る。これは最初のxが束縛された際の環境をマクロ展開器が知っているため、単なるシンボルであれば環境を閉じ込めて識別子にすることができるからだ。

あぁ、そうか。ならラップする際に何とかできればいいのか。いや、待てよ。同じ識別子なんだから、環境内でも同じか。結局簡単な方法はunrenameすることになるのか・・・

さて、もう一ひねりしてみるか・・・orz

2012-03-12

マクロとコンパイラと不具合と

ずいぶん昔から以下のようなマクロが動かない。
(define-syntax define-lambda
  (syntax-rules ()
    ((_ name formals body ...)
     (define name (lambda formals body ...)))))
(define-lambda test (t rest) `(t ,t))
(test 'a 'b) ;; => (t.xxxxxx a) xxxxxxは適当な16進数
なぜか?実は原因も全部分かっているのだが、直すに当たって余計な不具合を入れないためにもこれが必要だった経緯を書いておく。

そもそも、これは何か?
これはsyntax-caseのR6RSテストスイートをパスさせるために入れた苦肉の策である。
具体的には、syntax-caseを通った式はすべて識別子に変換される。その際に、識別子の同一性を保つため同一のsymbolであれば同一の識別子になるようにしている。

何故これは起きるのか?
上記のままでは拙い場合があった。問題としては一度識別子に変換されると2度目の変換ルーチン(以下renameと呼ぶ)ではそのままその識別子返してくる。その際に、ローカルに束縛された識別子が問題になった(と思う)。だが、マクロの展開器は賢くないのでコンパイラ側でローカルに束縛された識別子をシンボルに直してやる必要があった。また、その際に単に構文情報を剥ぎ取るだけではだめで、シンボルに直された識別子が一意である必要があった。
上記の例では(define-lambda ...)の中で「t」というシンボルはすべて同一の識別子に変換される。普通にquoteされるなら構文情報を剥ぎ取るだけなので問題ないが、quasiquoteまではunrename(と呼んでいる)ルーチンは見ない。そのため、quasiquote内の最初の「t」はunrenameされた状態で出力される。

どう解決するか?
解決方法は2つあると考えていて、unrenameがquasiquoteを見る。もしくは、unrenameをやめる。
前者は正直これ以上糞コードを増やしたくないので却下。後者はなぜunrenameなどと言うものが必要だったかという経緯を考えれば問題ない気がする。
つまり、renameルーチンが識別子を受け取った際に、その識別子をコピーしてやればいいはず。そうすれば、識別子が同一過ぎて困るという問題は無いはずだ。具体的にはwrap-syntaxという処理が式を識別子に変換しているのでそれをちょっといじって、コンパイラからunrename関係の処理をごっそり削ればいけるはず。

とりあえず試してみる。

2012-03-08

開発環境

ほぼ月1でリリースしてると、月1でフルビルドしないといけないということになっていて、Cygwin+非力なマシンでは厳しいなぁと思えてきた。
もっと非力なマシン+Linux GCCだと速いという事はやはりCygwinが遅いんだろうなぁと思い、何か別な環境はないかと探してみる。

とりあえず基準というか絶対条件として、
  • CMakeがサポートしてるコンパイラ
というのがどうしても入ってくる。そうするとどうしても問答無用で絞られてきて、現状の最新バージョン2.8.7ではGCC、MinGW、MSVC(含むVSプロジェクト)、Borland C++とWatcomであった。まぁ、GCCの部分はUnix Makefileなのでコンパイラ自体はなんでもいいのだが。結局Cygwinを避けるためには自前でmake相当のコマンドを持っているコンパイラになるわけだ。
っで、BCC32(フリー版の5.5)は僕が大学の時からバージョンアップしてないという記憶なのでさすがに10年以上前ではどうよ?と思いパス。(まぁ、こじゃれた最新機能はつかっていないのでOKな気もするが)となるとWatcomしかないじゃんと思い試してみた。

結論。BoehmGCすらコンパイルできなかった・・・orz

多分どこかCMakeLists.txtの記述がおかしいのだろうと思うのだが、Windows環境ではMSVC決め打ちの部分が多いので修正も大変。とりあえずwmakeが打てるところまできてこれが起きたので一気に気力が持っていかれた。

じゃあ素直にMSVCでいいじゃんと思うのだが、インストールに2G以上使うような富豪プログラムなのでHDDのスペースが足りない。(Cドライブが10Gしか切ってない上に、すでに8G使われている)
Windows SDKは問答無用で.NETがくっついてくるし、打つ手なし。

だれかいい案ないですか?

2012-03-07

DER, BER, CER?

ASN.1の代表的なエンコード(?)方式。
正直CERは見たことないのでよく知らないが、職業柄DERはよく見るしそれにくっついてBERもよく見る。

Sagittariusに(ようやく)ASN.1のバイナリを読むライブラリを入れたのでちょっといろいろ整理も兼ねて。
基本的な部分はBouncycastleの移植といった感じにしてあるので、クラスの継承関係もそんな感じ。
DERを読むならBERを読むのも簡単なので、DERを基本クラスにしてそのBERは派生。
Readerはタグみて読むだけなので、クラスの派生を知る必要はないが、両方読めるようにタグの種類でdispatchする感じ。
エンコードはおそらく本来はBERのオブジェクトも条件によってはDERを出力しないとまずいんだろうけど、面倒なのでBERだけ出力。つまり、BERを含む証明書(あるのか?)は読み込みしてDERだけに変換という荒業はできない。(これはそのうち何とかするかも。parameter使えば多分なんとかなる)
昔作ったASN.1のパーサーがあるけど、これどうしよう?一応バイナリと構文の整合性チェックに使う予定だったんだけど、やるのしんどい・・・

DERとBERの違いはなんぞやというGoogle検索の結果を勝手に予測して。
ここが詳しいけど、一応自分でも。
本質的には一緒。DERはタグ、長さ、データの順で書かれたバイナリ。タグは基本2種類あって、プリミティブと拡張(?訳語しらない)されたもの。最初の1バイトと0x1Fを論理積(and)した値が0x1Fなら続く数バイトはタグになる。
BERの方が機能的にはスーパーセットらしい(構築されたoctet stringとか?)。PKCS12形式の証明書群の中にあるのを見た。多分暗号化されたDERとか入れれるのだろう。(他のViewerで見るとどうもSagittariusのはうまく読めてないくさい。そのうち直そう)

2012-03-02

Sagittarius version 0.3.0リリース

リリースノートを書くのが億劫というか、何を直して何を追加したか思い出せん。もっとまめにChangeLog書かないと・・・

Sagittarius Scheme 0.3.0がリリースされました。このバージョンからCLOSが組み込みでサポートされます。ただし、すべての機能がサポートされているわけではありません。使用するには(clos user)もしくは(clos core)ライブラリをインポートしてください。

修正された不具合
  • internal defineされた値がマクロ内から参照できない問題が修正されました。
新たに追加されたライブラリ
  • (clos user) 及び (clos core)が追加されました。CLOS風のプログラムを書くにはこのライブラリをインポートする必要があります。
  • (text markdown)が追加されました。簡単なマークダウン形式のテキストのパース及びHTMLへの出力を行います。
  • (scribble)が(scribble parser)、(scribble convert)及び(scribble plugin)に分割されました。
  • (sagittarius document html)が追加されました。Sagittariusが作成するHTML形式のドキュメントを作成するのに使われています。
  • (getopt)が追加されました。SRFI-37の薄いラッパーです。
改善された機能
  • regex-replace-all 及び regex-replace-firstの第2引数がプロシージャを取れるようになりました。Javascriptの機能にinspireされたものです。詳しくはドキュメントを参照してください。
  • binary-port?及びtextual-port?がR7RS互換になり、ポート以外の引数を受け取ってもエラーを投げなくなりました。
  • get-bytevector-n及びget-bytevector-someのパフォーマンスが多少改善されました。内部的に2度メモリの割付を行っていたのが解消されています。
  • (sagittarius process)の機能が大幅に改善されました。JavaのProcessクラスの設計思想に基づいて書き換えられています。
  • (sagittarius threads)でしばしばデッドロックを起こす問題が解消されました。これによりドキュメントのサポートSRFIの欄に正式にSRFI-18が追加されています。ただしWindows上でthread-terminate!を使うと予期しない動作をします。現状確認されている不具合です。
新たに追加されたドキュメント
  • (sagittarius process)が正式にドキュメント化されました。

多分これ以上にいろいろいじったんだけど、思い出せない。

rebase問題+process

Sagittariusでプロセスの実装をしている際に、Cygwin上だとforkでころころ落ちてていらいらしていた。Cygwinのforkは不安定だという話は聞いていたので、こんなものだろうかと思っていたのだが、(実際、出てくるエラーメッセージもresource temporary not availableだったし)、いろいろ調べてみるとrebaseすると直るみたいな記事が山ほどあったので試してみた。

結果、あぁ、これだったのね、という感じで今はさくさく動いている。別段Cygwin上でプロセスを起動させることはないのだが、(これ自体Windowsのバッチでmavenのビルドスクリプトを書くのが苦痛で作ったものなので^^;)、動くとなるとなんらかに使えるかなぁとか考えてしまう。

と、これだけだと微妙なので、新生プロセスライブラリの概要でも。(誰も見てない?)
低レベルAPIのシグネチャ(これって日本語でなんていうの?)は特に変更なし。ラッパーで作っていたrunプロシージャが(name args)から(name . args)になって、書くのが多少楽になった。
今までは問答無用で標準入出力にリダイレクトしていたけど、パイプを通してSchemeからそれらの出力結果を取得できるようにした。(低レベルAPI)

実装上どうしようもなかったのだが、POSIX環境とWindows環境で微妙な差がある。POSIXだとプロセスの使い回しができるのに対し(PIDは一緒だが)、Windowsだとできない。これは、Scheme上では見えないけど、プロセスオブジェクトを作った際に実際にWindowsではプロセスを作ってしまうが、POSIXは後からforkとexecで実行するための情報を格納しているだけという違い。
設計思想的には両方ともWindows風にしてしまいたいが、僕の頭では無理。

理由:
プロセスオブジェクトを作成した段階でそれぞれのリダイレクト先にアクセスできるようにしたかった。でないと走らせる前に入出力のリダイレクト先を読み取るとか書き込むということができないから。また、作成と同時にプロセスが走るようにするとオブジェクトを作った意味が薄れるため。
誰かいい解決方法教えて。

2012-03-01

Win32プロセス

プロセスの実装を何とかしようとしているのだが、調べても答えが出てこない問題がでた。

現状、プロセスを作成した際に標準入力、出力、エラーを名前なしパイプに割り当てている。っで、プロセスは非同期もしくは同期(単に終了まで待つだけ)で起動できるのだが、MSDNを読むと作成されたパイプはバッファーの上限があるらしく、上限に達した場合読み取ってやらないと書き込みができなくなるという。
あんまりログを吐かないプロセスなら問題ないが、mavenでがりがりログを吐く上にコンパイルされるプロジェクトが20以上あるとなるとバッファーの上限はあっという間に超える。
じゃあ、読み取ってやればいいじゃんという話になるのだが、パイプから何かを読み取ろうとした際にまだ何も書き込まれていない状態だと現状EOFを返すのでループで回してもすぐ終了してしまう。っで多分デッドロックというかバッファーがいい感じに満杯になってうんともすんとも言わなくなる。
こういう場合って多くの処理系はどうやって対応しているのだろうか?
とりあえず、読み込みの方をいじった方がいいだろうか?

2012-02-29

うるう年

すっかり忘れていた。折角なので何か書いておこうというだけの話。

ここ数日(といっても今日で2日目だが)風邪ひいていて結構体がだるい。というか基本起き上がるとくらくらするのでベッドの中でごろごろしている。
早く治らないかなぁ。まぁ、でも明日は仕事にいくだろうけど。

2012-02-26

親の心子知らず

母親とは子供のことでいろいろ何か出来ないか模索せずにはいられない生き物なのだろうとちょっと実体験した話。

いろいろあって関係が壊滅的になっていた(今はほんの少し持ち直したと思う)のが事の始まり。昨日いきなり話し合いの場を設けられた。何故こうなったのかというのが主なもの。こういう話で原因がはっきりしていることってあるのかは知らないが、もし原因があるなら僕だろう。単にいろいろ覚悟が足りなかったという話だ。あんまり優秀な捕手ではないので、飛んでくる球を全部受けきれずという感じだ。(まぁ、直球すら落球していたという話ではあるのだが)
っで、一夜明けて今日、いきなりアントワープに行こうという提案が飛んできた。あぁ、いろいろ考えた結果「2人で何かをする」というのがそこだったんだろうなぁと瞬時に理解。でも、日曜のアントワープなんてただ歩くだけだし、疲れも溜まっていたのでお断りをした。んで、次がどうやらアムステルダムで買い物だったみたい。
正直どういった経緯でアントワープからアムステルダムになったのかは知らないけど、電話があって僕は行かないということを知った際の反応からこれもその一つだったんだなぁと理解。いろいろ申し訳ないなぁとは思いつつ、でも僕買い物に付き合わされても正直ストレスにしかならないんだよなぁとかも思ったり。
いろいろ好意を無にしてるなぁとは思うし、迷惑かけてるなぁとは思うけどう~ん。

甲斐性無しのダメ男ですいません。
(上記は既に謝ってるので、ネット上で言うなよというのはなしの方向で。ブログに書いてるのは単なるはけ口です。こういうとき日本語が分かる友人がオランダでほしいなぁと思う。)

2012-02-25

プロセスをちょっと本格的に実装

以前からとりあえず動く、というか単に他プロセスが呼べるレベル、のものはあったのだがさすがにこのままではなぁと思いちょっと改良(改悪?)してみた。

もともと設計の方針としてはJavaのProcessクラスみたいな感じで入力、出力、エラー出力のポートをプロセスが持っていてそれらをいじれるようにしようとしていた。っが、とりあえず全部標準入出力にリダイレクトして適当にしていた。
っで、ちょっと思い立ってまじめにそれらを割り当てることにした。まぁ上手くいってる。っが、ここでちょっとした問題が。
元々この機能は仕事でmavenを叩くのにWindowsのバッチでは厳しいなぁと思っていたから作ったのだが、今回の変更で標準出力にリダイレクトされないのでログが見辛い。また、走っているプロセスのパイプに対して出力があったのか知る方法がないので、出力ポートからログを上手く取得できないという問題がでた。
解決方法はいまいちいい案がないのだが、とりあえず出力のリダイレクト先を指定できるようにするとか、char-ready?(ポートはバイナリなのでu8-ready?か)的な何かをまじめに実装するか、プロセスが終了するまでじっと待ってからログ吐く(運用回避?)のどれかだろうか?

Rubyのspawnとかどうしてるんだろう?(使ったこと無いけど、いろいろ出来そうだなぁとドキュメント見て思った)

2012-02-23

Boehm GC "too many heap sections" error


Well, the reason why I am writing this article is it's not because I found the solution for that but I have figured out which version I could avoid this. So this is just a memo.

Boehm GC is one of the coolest library for C developer however it still has a lot of problems to use all platform (I guess). When I got this error, I was using Cygwin to develop my own project Sagittarius and trying to run tests. The GC version was 7.2 alpha 6. I actually used version 7.1 before and the reason why I tried to use the latest version was to solve multi thread problem. Well, as you can see it was a wrong decision. Each time I tried to run the tests it failed. So I decided not to use it and revised to stable (they say) version.

If you google this error message, you can probably see the solution which you need to build it with LARGE_CONFIG ld flag. Unfortunately, I haven't tried it because I also saw a lot of article which said it did not solve any problem.

Sorry if you google this error message to solve your problem, I have just written this article for nothing actually:-p

2012-02-20

宗教と家族

またこれ系のネタだ。まぁ、たぶんこれで最後だろうが。

あなたには彼女(もしくは彼氏)がいます。っでその兄妹がオウム真理教の信者であなたの彼女(彼氏)に「この宗教はすごくいいんだ」と勧めています。そんなときあなたはどうしますか?
  1. 止める
  2. 放置する
  3. 自分も改宗する
2もしくは3を選んだ方は続きを読んでもいらだつだけでしょう。

2012-02-17

常識で考えましょう...

Togetterにあったまとめ
@May_Roma流英語習得法:「常識で考えましょう…」
おおむね賛成なんだけど、微妙だなぁと思ったのが1個。(実は最初の15個くらいしか見てないので他にもあるかもしれないが)
https://twitter.com/#!/May_Roma/status/168427967175860225
 日本語力つけたい外人が、日本語でちゃんと喋ったり書いたりできないDQNに日本語習ってもうまくなるわけないでしょう。英語も同じでまともな先生に高い金を払って習わないとうまくなるわけないです。高い先生は自分の勉強に投資してんですよ。常識で考えましょう…
前半は非常に賛成なのだが、後半は実体験からそうでもないなぁというのがあったりする。

とりあえず「日本国内で勉強する」ということに絞るとすれば、当てはまるのかもしれないが、E○Cとかの英会話学校だと「高いけど先生はまともじゃない」なんてことがままある。実際僕も日本で英会話学校にいっていたのだが、あまりたいした成果はなかったような気がする。もちろん0ではないし、その後カナダに行った際に役に立ってはいたので無駄ではなかったとは思うが。この場合はおそらくここで言う「まともな先生」というのがキーワードなんだろう。それを探すのにスキルがいるということだ。

個人的に上記はとりあえず僕が思ったものでも小さいもので、大きくそれは違うだろうと思ったのは、この文章から見て取れた「金を払わないと英語は習得できない」というもの。(国語の点数は低い方だったのでそんなこと言ってないと言われると以下は破綻します)。
僕がある程度(ビジネスでも使える程度)英語が喋れるようになったのは高い金を払って先生から授業を受けたからではない。どちらかといえばそのような環境にいるからだと思っている。つまり英語で仕事をする環境にいるということ。同じことが日本で働いていた時にも言えて、大学を卒業してから身につけた日本語というものが非常にたくさんある。(御社とか弊社とか学生時代は知らんかった)
「習うより慣れろ」という言葉があるように実際に使われている言葉に触れるというのは何者にも代え難い勉強方法ではないだろうか。ただこれを言うと、

勉強なら他所でやれ
この学生の間違いは、会社に入って給料を貰いながらスキルアップしようと思っていること。小学生から大学まで16年学ぶ時間がありました。就職して仕事を するということは、学んだことを生かしてアウトプットするということ。まだスキルが足りないというのなら、その必要なスキルが学べる専門学校にでも行けば いい。会社に入ってスキルアップなんて図々しいことこの上なく、給料は貰うどころか、授業料を払うべきです。会社でのスキルアップというのは仕事の結果と してそうなるわけであり、それ自体を目的にするのは本末転倒。
上記の意見に当てはまる気がするのでそれはそれで微妙かもしれないが。ただ、現場で使われている言葉という点に焦点を絞るならそこにいなければわからないこともあるだろうということだ。
実際、僕もここで働き始めて英語の勉強をせざるを得なかった。具体的には電話の応対とかね。そうはいってもそれに対して金は払ってない(ネット代は含まない)。

効率という点を除けば手段はいくらでもあるはずだ。
「まともな先生」というのが人間以外も指すなら、高い金を除いて賛成ではあるが。

2012-02-12

BNFを書いてみた

Daring Fireball: MarkdownのDingusにあるチートシートからBNFを起こしてみた。無ければ作るのがナンとやら精神で。
BNF of Markdown,

Doc ::= Element*
Element ::= Paragraph | Header | List | Blockquote | Line
         |  CodeBlock | BlockHtml | Reference
Paragraph ::= Inline* Linefeed{2,}
Inline ::= (Text | Emphasis | Link | Image | CoseSpan )
Header ::= Setext-Style | Atx-Style
Setext-Style ::= Text Linefeed ('=' | '-')+
Atx-Style ::= '#'{1,6} Text '#'*
List ::= (Number '.' SP+ Inline+) (Linefeed List)*
      |  ('*' SP+ Inline+) (Linefeed List)*
Blockquote ::= '>' SP* Paragraph
            |  '>' SP* Linefeed (Blockquote)*
Line ::= ( (SP* '-') | (SP* '*') ){3,} Linefeed
CodeBlock ::= SP{4,} Inline+ Linefeed
BlockHtml ::= '<' (div|p|table|pre) '>' (Text | BlockHtml)+ 
              '<' '/' (div|p|table|pre) '>'
Text ::= ANY
Emphasis ::= '*' Text '*' | '**' Text '**'
          |  '_' Text '_' | '__' Text '__'
Link ::= '[' ID ']' '(' URL ('"' Text '"')? ')'
ID ::= Text
Image ::= '!' '[' ID ']' '(' URL ('"' Text '"')? ')'
Reference ::= SP{0,3} '[' ID ']' ':' URL ('"' Text '"')?
実装にある正規表現を追ったわけではないのでかなり微妙かつ、BNFの書き方をあんまり良く知らないので正しくはないかも。ルールに書いてないもので、SPとANYはそれぞれスペースと文字(二つ以上続く改行を除く)。Linefeedは改行で。

> Markdownに詳しい方
間違っている可能性が大いにあるので突っ込み大歓迎ですm(_ _)m

2012-02-11

Markdownがいるのだが

一つ前の投稿に関連するのではあるが、Markdown形式で書かれたテキストをHTMLに変換するスクリプトがいる。本家を使えばいいといえばそうなのだが、それでは面白くないのと、ちょっとした理由でSagittarius上のライブラリとしてほしいわけだ。
っでとりあえずいろいろな実装をみてみたが、どれもこれも正規表現でテキストからHTML一気に(まぁ多少ごにょごにょしているが)変換している。そんな中peg-markdownはCで書かれているがPEGでパーサーを作成している。とりあえず参考になるかもしれないと思い文法ファイルを見てみたが、信じられないぐらい複雑な文法をしていた。
正直あんな複雑な文法をガリガリPackratで記述するよりは手書きでパーサー書いた方が早い気がする。あとPackratは割りと機能が足りてない感じがするのでどうしても冗長に書いてやらないといけなくて結構大変というのもある。これはCSVのパーサ書いて感じた。あんな簡単な文法なのに結構面倒だった。

一番楽なのはshowdown辺りの実装を移植することかなぁと思っている。っがテキスト→HTMLと一括でやっちゃうのは正直面白くなくて、テキスト→AST→HTMLと一枚噛ませたいなぁと思っている。問題はこれだと正規表現とは非常に相性が悪く、自前パーサーが必要になる。とりあえず動くものなら前者の実装でもいいのだが、う~ん。
誰か簡単なBNF定義してくれないかなぁ・・・(他人任せ)

ChickenのPackrat

Markdownのパーサーがいるのでpackratを使ってパーサを書こうとしたのだが、いまいち使い方が分からなかった。なので、練習がてらCSVのパーサを書いてみることにしてみた。
とりあえずいい加減なパーサがこんな感じ。
(import (rnrs)
 (packrat)
 (srfi :14 char-set))

(define *text-set* 
  (ucs-range->char-set! #x2d #x7e #f
 (ucs-range->char-set! #x23 #x2b #f
       (ucs-range->char-set #x20 #x21))))
(define (any results)
  (let loop ((acc '()) (results results))
    (let ((ch (parse-results-token-value results)))
      ;; it's just testing
      (if (and ch (char-set-contains? *text-set* ch))
   (loop (cons ch acc) (parse-results-next results))
   (make-result (list->string (reverse! acc)) results)))))
(define (textdata results)
  (any results))

(define parser
  (packrat-parser 
   (begin 
     (define (crlf results)
       (let ((ch (parse-results-token-value results)))
  (case ch
    ((#\linefeed) (make-result "" results))
    ((#\return)
     (let ((ch (parse-results-token-value (parse-results-next results))))
       (if (char=? #\linefeed ch)
    (make-result "" results)
    (field-entry results))))
    (else (field-entry results)))))

     file)

   (file    ((h <- header '#\linefeed r <- records) (cons h r))
     ((r <- records) r))
   (header  ((n <- names) (cons :header n)))
   (records ((f <- fields '#\linefeed r <- records) (cons (cons :record f) r))
     ((f <- fields) (list (cons :record f))))
   (fields  ((f <- field-entry '#\, fs <- fields) (cons f fs)) ;; (1)
     ((f <- field-entry) (list f)))
   (names   ((n <- field-entry '#\, ns <- fields) (cons n ns))
     ((n <- field-entry) (list n)))
   (field-entry ((e <- textdata) e))))

(define (generator p)
  (let ((ateof #f)
 (pos (top-parse-position "")))
    (lambda ()
      (if ateof
   (values pos #f)
   (let ((x (read-char p)))
     (if (eof-object? x)
  (begin
    (set! ateof #t)
    (values pos #f))
  (let ((old-pos pos))
    (set! pos (update-parse-position pos x))
    (values old-pos (cons x x)))))))))

(define (parse-csv p)
  (let ((result (parser (base-generator->results (generator p)))))
    (if (parse-result-successful? result)
 (parse-result-semantic-value result)
 (apply assertion-violation
        (let ((e (parse-result-error result)))
   (list 'parse-csv
         (parse-error-messages e)
         (parse-position->string (parse-error-position e))
         (parse-error-expected e)))))))
(call-with-input-file "test.csv"
  (lambda (p)
    (parse-csv p))))
#|
入力ファイル
aaa,bbb
ccc,ddd,eee
fff,ggg,hhh
a,b,c
出力
((:header "aaa" "bbb")
 (:record "ccc" "ddd" "eee")
 (:record "fff" "ggg" "hhh")
 (:record "a" "b" "c"))
|#
generatorはドキュメントにあったものをちょっと改変しただけ。多分これが基本なんだろう。
かなり適当で本来はCRLFなのがLFだけだったり、エスケープされたものを認識しなかったりするがまぁ動く。気になったのは「/」の使い方で、こんな感じには使えないという不便さであった。
(entry (((/ (e <- escaped) (ne <- non-escaped))) (if e e ne)))
展開されたコードをみたらまぁ納得なのだが、これがやれないとなると結構面倒だよなぁ。あとこのライブラリは「*」とか「+」とか「?」がないので、それらを書こうと思ったら、(1)のように条件を2つ作る必要がある。

やっぱり正規表現をつかってやるべきだろうか。

2012-02-09

srfi-22

現状部分的に実装しているのだが、もう少しまじめに実装するべきだろうか。単にmain関数を特別視するかどうかというだけだが。
正直実装自体は非常に簡単なので(2~3行足すだけ)やるなら悩むことも無く終わるのだが、どうしよう。毎回(command-line)を呼び出すよりは(main args)と書いて参照できた方が楽だよなぁ。特に使い捨てのスクリプトならなおさら。

やるか。

2012-01-31

CiSEみたいなのがほしい

願望的に書いているが、現在使っているスタブジェネレータがちょっと使い辛くなってきた。いや、別に使い辛くはないのだが、拡張性が皆無だなぁということに気づいたのと、結構他のヘッダーファイルべったりな構成になっているのでSchemeのファイルなおしてCのヘッダー直してというのが面倒になってきた。
っで、GaucheのCiSEを眺めていたらすごく抽象化されていて美しいコードだなぁと。たぶんそのまま移植できるんだろうけど、それやったら面白くない上に結局理解してないから自分で拡張できない。ということでコードの分析。

基本的にほしい機能の部分としては、gauche.cgen.cise、gauche.cgen.stubの2つ。っでこれらが大きく依存しているのが、gauche.cgen.unit(以下ユニット)、gauche.cgen.literal(以下リテラル)。ツール的になのかフックなのかはまだ見てないけどgauche.cgen.typeがstubファイル内での<object>形式の記述をCに変換している。
ユニットではCのプリプロセッサと生のコードを扱う。生のコードがどう書かれるのかは知らない。それぞれを扱うクラスがあって、それぞれをどう出力するかの総称関数がある。
リテラルはSchemeのリテラルをCに変換するモジュール。リストとか文字列の変換。リテラルクラスが上記のユニットを継承して定義される。
CiSE内では基本的な変換部分しか定義されず、その他のモジュールでGauche固有の定義が入る。ただ、そうは言ってもCiSE内で定義されている構文にはScmObjとか入ってくる(let*とかfor-eachとか)
また、CiSEは環境を保持していて、トップレベル、ステートメント、式の3つがある。たとえばdefine-cfnはトップレベルでしか定義できないし、beginは全部いけるんだけどそれぞれ出力されるCのコードが違う。

とりあえずここまで踏まえて、まずどこまでやるかを考える。
  • 特に純粋なCファイルを出力する必要はない
  • 現状のStubファイルとVMインストラクションの手直しはがっつりやってもOK
  • SchemeファイルをCにする必要はない(gauche.cgen.precompモジュール相当はいらない)
として、方針。
  • ノード毎のクラスは取り入れたい
  • 環境+render部分を移植(だめじゃん)
  • 純粋なCiSE部分、Sagittarius固有定義というようにする
とした場合、ライブラリの構成を考えると、こんな感じだろうか?
                   +--------------+       +-------------+
                   |     CiSE     | ----- |     Unit    |
                   +--------------+       +-------------+
                          |                      |
                   +--------------+       +-------------+
                   |    Syntax    |       |   Literal   |
                   +--------------+       +-------------+
                          |                      |
                   +--------------+              |
                   |     Stub     | -------------+
                   +--------------+
CiSEではSagittariusに依存しない構文までサポート。letでは総称関数を作ってデフォルト型の定義を下位のライブラリで行うようにする。デフォルトの振る舞いはエラーでいい気がする。
SyntaxではSagittariusに依存する構文を入れる(for-eachとか)。
Stubは単なるエントリーポイントになるか、それとももう少し何か入れるかは考えてない。

2012-01-26

CLOSの動作チェック

0.3.0に備えてCLOSの動作チェック。組込みでCLOSをサポートするため。でもCL並みに高性能にするべきか悩み中。

とりあえず、Tiny CLOSをベースにしようと考えていたので、サポートしてるmoshで検証。ただ、moshのCLOSってうっかり変なことするとすぐにハングアップするので注意が必要。せめて構文エラーとかそんなメソッドないとか言ってくれればいいのに。
今回はaround、before、after、primaryについてちょっと調べてみた。結論を言うと、完全Aspect指向って感じ。検証コードは以下。
(import (rnrs) (clos core) (clos user))
(define (print . args)
  (for-each display args) (newline))

(define-class <person> () name age)
(define-method initialize ((p <person>) init-args)
  (initialize-direct-slots p <person> init-args))
(define-class <painter> (<person>) pen)
(define-method initialize ((p <painter>) init-args)
  (call-next-method)
  (initialize-direct-slots p <painter> init-args))

(define koch (make <painter> 'name "Koch" 'age 18 'pen "Brush"))
(print (slot-ref koch 'name))
(define-generic paint)

(define-method paint 'arround ((p <person>) colour)
  (print "starting messing up")
  (call-next-method)
  (print "ended messing up"))
(define-method paint 'arround ((p <painter>) colour)
  (print "starting")
  (call-next-method)
  (print "end"))

(define-method paint 'before ((p <person>) colour)
  (print "messing up " colour))
(define-method paint 'before ((p <painter>) colour)
  (print "preparing " colour))
(define-method paint ((p <painter>) colour)
  (print "painting " colour))
(define-method paint 'after ((p <painter>) colour)
  (print "painted " colour))
(define-method paint 'after ((p <person>) colour)
  (print "messed up " colour))
(paint koch 'red)
#|
Output:
Koch
starting
starting messing up
preparing red
messing up red
painting red
messed up red
painted red
ended messing up
end
|#
aroundがarroundになっているのは仕様です。aroundだと動かない・・・そしてmoshが死ぬ。
beforeはprimaryが呼ばれる前で、順番は子から親へ辿る。
afterはprimaryが呼ばれた後で親から子へ辿る。
aroundは見たとおりで、すべての処理の前と後。ただし、call-next-methodを呼ばないと本処理が走らない。また、同じメソッドがあれば、子から親の順で呼ばれる。
aroundはcall-next-methodをコメントアウトしたりすると理解が早い。たとえばのaround内にあるcall-next-methodを消すと、子->親->子で終了する。aroundを指定したら必ずcall-next-methodを呼ばないとえらいことになる。
Java等ですでにAspect指向をやったならあれとほぼ一緒だろう。表面的なことしか見てないけど。

問題は、どうこれを実装するかだな・・・

2012-01-19

Cygwinのdlsym

Google先生に聞いても今わからないなぁ。とりあえず何が起きたかメモ。

SagittariusにCLOSを入れようと組み込みクラスを実装して、拡張ライブラリの方も書き換えたら動的呼び出しが失敗するようになった。理由は分からない。
確認できていることとして、Windows(MSVC)とLinux(Ubuntu、GCC)ではOK。ただ、Windowsでもそうなんだけど、Cygwinではリンカーが死んでるのか腐ってるのか知らないが、普通にコンパイルするとinitializer is not constantとか変なメッセージがでて怒られたのでC++でコンパイルしてる。VCではOKでg++では駄目だということなんだろうか?
それとも、CでコンパイルされたDLLからC++でコンパイルされたDLLを呼び出せないとか?nmコマンドで調べるとシンボルはあるから、extern "C"とかそんなレベルではないはず。(正しくdllexportとか書けてるか自信ないと言えばないが・・・)
こんなリンカーの内側の動作を知らないと駄目というのは結構厳しい。

しかし、もう少しまともなエラーメッセージでないのかねdlsym()も。No errorって、見つからないからNo errorですか?
誰かヒントください。意味不明すぎて涙でそう・・・バイナリアン検定は落ちるなこりゃ。

追記
一晩寝たら原因がわかった。__declspec(dllexport)がCygwinにはついてなかった。ってか、CではOKでC++だとアウトかよ!!たぶん名前マングルのせいだな。

2012-01-17

Version 0.2.4リリース

もう少しいろいろテストしてからでもよかったかもと思いつつ。

Project page (in English)

Sagittariusバージョン0.2.4がリリースされました。このリリースからCommon Lisp風のリーダマクロが使えます。またR7RS(draft 5)をサポートしました。同ドラフトが要求している構文およびライブラリ(1部除く)をサポートしています。一部リーダが読み込むシンボルに違いがありますが、これはSagittariusがGauche風のキーワードをサポートしているためです。

修正された不具合
  • GC周りの不具合が修正されました。これはBoehm GCのライブラリを静的リンクしていたため起きた不具合です。現在ではGCライブラリを動的リンクしています。
  • define-with-keyがGauche風に動くよう改善されました。
  • 正規表現リーダが[[:char-set:]]を正しく読まない不具合が修正されました。
  • equal-hashが停止しない不具合が修正されました。
  • equal?で作成されたハッシュテーブルがバイトベクタを格納できない問題が修正されました
  • list->stringに文字列リストを渡してもエラーにならない不具合が修正されました。
  • マクロ展開周りの不具合が修正されました。詳しくはプロジェクトページのIssue 7を参照してください。
  • 3.1415|10といった仮数を指定している数字が読めるようになりました。ただし仮数は無視されます。
  • quotient、moduloおよびremainderの第二引数に0を渡すとSIGSEGVが発生する問題が修正されました。
  • 正規表現リーダが\0mnn、\xhh、\uhhhhおよび\Uhhhhhhhhが正しく読み込めなかった不具合が修正されました。
新たに追加されたライブラリ
  • (shorten)ライブラリが追加されました。lambdaを^と書けます。
  • (scheme repl)以外のR7RSのライブラリが追加されました。
  • JSONパーサライブラリ(json)が追加されました。Chicken Schemeからの移植です。
  • Packratパーサライブラリ(packrat)が追加されました。Chicken Schemeからの移植です。
新たに追加されたプロシージャ
  • string-splitが(sagittarius regex)ライブラリに追加されました。
  • secure-randomが(crypto)ライブラリに追加されました。
  • dolist、cond-list及びslicesが(util list)に追加されました。Gaucheからの移植です。
  • cond-expandが組込構文になりました。
  • define-libraryが組込構文として追加されました。R7RSのライブラリ構文です。
  • include及びinclude-ciが組込構文として追加されました。R7RSライブラリ構文外でも使用可能です。
  • #!fold-case及び#!no-fold-caseが追加されました。
新たに追加されたドキュメント
  • (crypto)ライブラリがドキュメント化されました。
  • (math)ライブラリがドキュメント化されました。
  • R7RSのサポートに関するドキュメントが追加されました。

2012-01-13

続R7RSモジュール

今回は舞い上がらずに自分の中だけで。
ChatonのGauche部屋に以下の書き込みがあった。(Twitterで見てるので分かった。便利な世の中だ)
okuoku
http://compassoftime.blogspot.com/2012/01/r7rs.html R7RSライブラリ構文が来るのか
nmoshはcond-expandのfeatureとキャッシュの関連が微妙なので保留中。。
実はキャッシュの問題はまだ残っている、というか諦めていて、Sagittariusではそもそもマクロ展開後にマクロが変更されてもキャッシュは更新されない。これぐらいなら何とかなるかもしれないが面倒でやってない。
しかし、include系はまず無理で、includeされたファイルの変更を検知する方法がない。なのでinclude先が変更されてもinclude元が更新されない限りキャッシュは作り変えられず切ない思いをする。この辺キャッシュの考え方が多分moshとは違って、ライブラリとして変更がない、もしくは少ないファイルがキャッシュされるべきという風に考えている。つまり、開発中ならキャッシュをクリアすればいいだけの話で、実際に使用するならライブラリ自体に手を入れないよね?っていう考え。
ただ気になるのはcond-expandのlibrary句で、あれば本家を使ってなければ自前みたいな風に分けられるだろうと考えているのだが、それやって後から本家が追加されたらどうするの?みたいな問題はある。(まぁ、その場合もキャッシュクリアしてくださいと言うだろうが)

どうでもいい話だが、ライブラリ構文に関してはR7RSの方が優れている気がする。cond-expandが標準で入ったのもそうだが、以下のように書けるのがでかいと思う。
(define-library (a library)
   (import (scheme base))
   (export a-procedure)
   ;; importが複数回でてもOK
   (cond-expand
     ((library (srfi :1))
      (import (srfi :1)))
     (else
       (define (acons a b c) (cons (cons a b) c))))
   (begin
     (define (a-procedure) ...) ;; something nice
   ))
R6RSではimport句はライブラリ中ただの1回しか出現してはいけないし、トップレベルでも厳格にやるとcond-expandで切り分けることもできない。(おかげでテスト用のプログラム書くのに苦労する。毎回コメントアウトしないといけない)
define-libraryを使った方がポータルに書きやすいかもしれない。未だにChibi Scheme以外でサポートしている処理系を知らないが・・・
ポータビリティを大分捨てているのに何を今更という感はあるが、テスト用書き捨てプログラムを書くのに便利になるのはいいことだ。

2012-01-12

R7RSモジュール

次のリリースではドラフト5(たぶん確定だと信じる)のR7RSモジュールシステムが入る。まだ、include-ciがダミーな実装だがそれ以外はだいぶよさげ。
以前exportやincludeが(scheme base)からエクスポートされていないと書いたが、まじめに実装して「されていなくてもいいのか」とちょっと納得した。(includeに関しては他で使えてもいいかなぁと思ったのでexportされていてもいいんじゃとは思うが。これってR5RSで書かれたものの再利用が簡単にできるための措置なんだろうか?)

R7RSで定義されているライブラリの内、(scheme repl)は次のリリースでははずすことにした。というかinteractive-environmentが必要になる場面が想像できないのと、(scheme base)等のライブラリがimportされた環境をREPLに用意するのが大変なため。
R7RSのモジュールはコアなライブラリではなく、現状sitelib扱いにしている。libとsitelibで何が違うかといわれると大分混ざってしまった感があるので答えづらい。

構文も(たぶん)網羅されてるはず。(#u8とか)。ベクターはもともとself evaluateだったので問題なし。微妙な問題だが、#!r7rs(#!compatibleと現状は一緒、つまりデフォルト)をつけると`#`がnon-termな文字になる。つまりabc#vu8(1 2 3)というのはabc#vu8というシンボルと(1 2 3)というリストに分かれる。#!r6rsをつけるとabcと#vu8(1 2 3)になる。0.2.4から入るリーダマクロのおかげでかなり簡単に実装できている。

chibi-schemeに次いで2番目と言えるかはわからないが、割と早めにR7RSのサポートをしていると思う。(ライブラリはmoshのr7rs-bridgeから大分もらったが)

2012-01-08

人間失格

太宰治ではない。(読んだことないなぁ、そういえば)

個人的な人格の欠陥の話である。よくも悪くも僕は淡白だと思う。というよりは人に対して一定以上の興味がわかないというべきか。正直いろいろなことを生活習慣にしていかないと傍から見た際にまったく興味がないと思われるらしい。というか既に思われた。
よくよく考えてみると自分のネコ好きというのも、その昔に自分で作った習慣のような気がする。昔から家にはネコがいるのが当たり前だったのでそれが簡単だったのだろう。
別段自分が無味乾燥な人間ではないと思うのだが、どちらかと言えば引きこもり系な性格ではあると思う。嫌なこと、楽しいこと、すべて自分の中だけで完結して表に出さない。内側で驚いていても、表面には出さないので、僕は滅多なことでは驚かない人間、と思われている。(まぁ、お化け屋敷程度では驚かないが)

3つ子の魂100までなんて言われるように、これを今から変えるのは難しいだろう。変えようとも思っていない。元々自分の理解者は自分だけでいいと思っている上に、人からの理解を期待していないというのもあるだろう。経験的に期待しても裏切られるというのが刷り込まれているからかもしれない。

何が言いたいというわけではないが、振られてそんなことを思った次第。
オランダに居る理由がなくなった日の夕方。

2012-01-07

結局

Gaucheがあの方式を取れるのはMakefileを自前で書いてる(automakeではない)からであって、CMake使ってると不可能な気がしてきた。

しょうがないのでREADMEに注意書き書いてdllでリンクするようにビルドした方がいい気がする。VCでコンパイルした際にどうしようかなぁというのと(gcmt-dllとリンクできなかった。何でだろう?)、オートダウンロード機能をつかってCygwinでコンパイルした際に問題になるけど。(GCのオートダウンロードはVCだけにすればいいだろうか?でも微妙だよなぁ・・・)
そもそもGCを静的リンクにしようとした理由ってなんだっけ?

2012-01-06

足元固め(バグつぶし)

ようやく不可解なメモリ関連の原因が特定できそうな気がしてきた。
現状、同じCygwinで起きる場合と起きない場合があった。今までどちらも同じ環境でビルドしていると思っていたが実は違った。片方はGCのDLLを使っていて、もう片方は静的リンクしてた。DLLの方はメモリを壊さないけど、静的リンクは壊していた。
今までメインのDLLにGCが入っていればモジュールとして呼ばれるDLLはリンクしなくてもいいと思っていたがそうでもないのだろうか?

ちょっと調査しよう。

sxpathメモ

SXPathで名前空間付のSXMLにクエリーを発行するのがいまいち分からなかったのでメモ。
正直これが正しいのか良く分かっていない。
(import (text sxml ssax) (text sxml sxpath) (pp))
(define *xml* "<?xml version=\"1.0\" ?><root xmlns:h=\"http://localhost/\"><h:p>hello</h:p></root>")
(define *namespace* '((h . "http://localhost/")))
(let ((sxml (ssax:xml->sxml (open-string-input-port *xml*) *namespace*))
      (sxml2 (ssax:xml->sxml (open-string-input-port *xml*) '())))
  (pp sxml)
  (pp sxml2)
  (let ((doc ((sxpath '(root h:p)) sxml))
       (doc2 ((sxpath '(root h:p) *namespace*) sxml2)))
    (pp doc)
    (pp doc2)))
#|
(*TOP* (@ (*NAMESPACES* (h "http://localhost/")))
       (*PI* xml "version=\"1.0\" ")
       (root (h:p "hello")))
(*TOP* (*PI* xml "version=\"1.0\" ")
       (root (http://localhost/:p "hello")))
((h:p "hello"))
()
|#
パース時に名前空間を与えてやるとタグをプレフィックス付でパースする。与えないとそのまま長い名前で出力する。
プレフィックス付のSXMLをsxpathに渡すなら、名前空間は要らない(あってもよい)。
プレフィックスなしをsxpathに渡すなら長い名前で指定する必要がある。名前空間渡しても識別しない。
ここに使い方があった。
Re: SXPath namespaces - msg#00006
どうやらsxpathの第二引数は微妙な動作をするくさい。上記の例だと
(pp ((sxpath "//root/h:p" *namespace*) sxml2))
#|
((http://localhost/:p "hello"))
|#
これで通る。S式なクエリでは認識しないが文字列ならOK。いまいちssaxとの相性が悪いというか、完全別モジュールという感じだ。

2012-01-04

マクロ戦争再び

分かってはいたことだがsyntax-caseがバギーである。
笑ってしまったのは、明らかに意図していない動作をするコードであることでR6RSテストスイートがパスできること。バグの上に成り立つコードなんてイヤだ。

ということで何が問題かを洗い出し、対策を考えることにする。
問題とするコードはとりあえず以下のものだけに絞る。
(define-syntax loop
  (lambda (x)
    (syntax-case x ()
      ((k e ...)
       (with-syntax ((break (datum->syntax #'k 'break))
         #'(call-with-current-continuation
             (lambda (break)
               (let f () e ... (f)))))))))
(let ((n 3) (ls '()))
  (loop
   (if (= n 0) (break ls))
   (set! ls (cons 'a ls))
   (set! n (- n 1))))
これはR6RSの仕様書にもあるキーワードを追加しないloopマクロの実装。現状ではbreakは存在しないといわれて怒られる。(でもテストケースでは通る)
loopは以下のように展開されることがコードから読み取れる。
(let ((n 3) (ls '()))
  (call-with-current-continuation
   (lambda (break)  ;; *1
     (let f ()
       (if (= n 0) (break ls)) ;; *2
       (set! ls (cons 'a ls))
       (set! n (- n 1))
       (f)))))
ここで問題になるのは、*1のbreakと*2のbreakが同じ識別子にならないこと。現状の実装ではマクロ内にあるパターン変数と実際に展開されるコード内にあるシンボル(識別子)が同じと考えられそうなら同じものを使うということをやっている。
正直それが正しいかどうかは分からないが、マクロ展開器は(特にこのパターンでは)どの識別子がローカルに束縛されているのか知ることが出来ない。これがネックになって上記のようなことを行っている。
まぁ、それはおおむね上手くいっている感じなのでそれを突き詰めるようにしていこうと思う。
上記の例だけ見れば、パターン変数としてのbreakはマクロ作成時に取得せざるを得ない。このとき取得したパターン変数含む環境をマクロ環境とする。マクロ展開時にはこのマクロ環境からbreakパターン変数を探すことになる。
現状で何が問題か?なぜか見つかったパターン変数が識別子ではなくシンボルになっていた。実際テンプレートないでbreakが見つかると、with-syntaxで作ったbreakがパターン変数として認識されるため置き換えが発生する。その際になぜか置き換えられたパターン変数が識別子ではなくシンボルであった。
考えられそうなこととして、with-syntaxは以下のように展開される。
(syntax-case x ()
  ((k e ...)
   (syntax-case (list (datum->syntax #'k 'break)) ()
     ((break)
      (let ()
        #'(call-with-current-continuation
            (lambda (break)
              (let f () e ... (f)))))))))
この際にパターンに与えられるS式からシンタックス情報が剥ぎ取られている可能性がある。

この問題の原因が分かった。datum->syntaxがシンボルを識別子にしていないんだ。なんらかの理由があって識別子のライブラリとマクロ環境(もしくは現在の環境)が保持しているライブラリが一緒だった場合ラップしないようにしてたんだ。なんでだったかな?

(続)R7RSドラフト5

ここから大きく変更はないだろうと仮定してdefine-libraryの実装に踏み切ろうかと思う。
定義を見ると、export、import、begin、include、include-ci、cond-expandがlibrary declarationとして定義されていて、それらが中に何度出てきてもよさそうな感じである(一回だけとか書いてないからそう読む)。
問題になりそうなのはexport、import、とcond-expandあたりだろう。
exportが2回以上出てきた際の扱いが書いてない。 両方をexportするのか、エラーではじくのか、処理系依存になるのだろうか?
importが複数回でた場合も特に記載がない。例えば以下のケース。
(define-library (import test)
  (import (scheme))
  (begin
    (define test 'a)
    ;; lazyは(scheme lazy)で提供されるが、
    ;; この場合はどう解決する?
    (define llist (lazy (cons 'a 'b))))
  (import (scheme lazy))
)
importの順番は関係ないのか、それとも上から順なのか。最終的な呼び出しは、Sagittariusの構造上importの順番は関係なのだが、マクロ展開についてはimportされた後しかマクロはつかえない。この場合上から順に解決すると、lazyはマクロではなく単なるプロシージャとして扱われる。どっちがR7RS的には正しいのだろうか?
cond-expandは現状では解決するのに外部ファイルを読み込む必要がでてくるので、ビルトインにする必要がある。ただ、libraryフィーチャが追加されているのでこれをどうするか。意図としては以下のようなものだろう。
(define-library (cond-expand test)
   (cond-expand
     ((library (srfi s1)) (import (srfi s1)))
     (else ;; 必要そうなリスト操作の自前実装
      )
)
あれば便利なんだろうけど、キャッシュとの兼ね合いが非常に悪くなりそう。R6RSで不便だった部分が解消されるイメージではあるが。
単純にR6RSのlibrary構文のエイリアスでは無理そうなので別途ビルトインシンタックスを作る必要がある。
素人目に見て結構微妙な構文に見えるがどうなんだろう?

2012-01-02

R7RSドラフト5

ちょっとまじめに眺めている。
その際に見つけた気になる部分のメモ。

2.1 Identifiersより
All implementations of Scheme must support the following
extended identifier characters:
! $ % & * + - . / : < = > ? @ ^ _ ~
「:」は識別しじゃないとだめらしい。キーワードはだめってこと? (拡張という扱いにしよう、そうしよう)

4.2.1 Conditionalsより
caseはcond同様=>をサポートしないといけないらしい。

4.2.5 Delayed evaluationより
eagerって何だ?
The eager procedure returns a promise which when forced
will return obj . It is similar to delay, but does not delay
its argument: it is a procedure rather than syntax.
procedureが望ましいってあるだけで、syntaxでもいいのね。あいまいじゃね?

4.3.3. Signalling errors in macro transformersより
(syntax-error <message> <args> ... ) syntax
procedureじゃねぇ!!

5.2.3. Multiple-value de finitionsより
define-valuesが追加されている。

5.5.1. Library Syntaxより
cond-expandが<library declaration>に入ってる。どうしたものかね。

6.11. Exceptionsより
error-object系のプロシージャをどうしようか。R6RSのコンディションでいけるか?

6.13.4. System interfaceより
loadがenvironmentを引数に取るんだけど、えっ?って感じなんだが。う~ん。
evalのファイル版みたいなもの?

リテラルなリストの扱いが面倒だなぁ。

謹賀新年

Happy new year!!
Beste wensen, gelukkige nieuwjaar!!
本年もよろしくお願いいたします。

元旦はわりと忙しくてかけなかった。

今年の抱負(というか目標)
  • 週2くらいでジムに行く
  • オランダ語を話せるようになる
  • ギターを毎日少しでもいいので練習する
書いておいて年末にできたかどうか確認しよう。
去年は個人プロジェクトを発足するということを書いたみたいだ、目標達成ではあるか?

個人的な近況報告できるほど変化があったわけではないのが寂しい。

以下はSagittariusな話題。


2011-12-29

括弧ゴルフ

折角リーダーマクロを作ったし括弧ゴルフでもしてみるかとやってみた。以下のサイトのルールで。
本当にLispはカッコが多い?
最後にあるLispのリーダーマクロを参考にGaucheのfoldを使ったケースを実装してみた。
#! /usr/local/bin/sash
(set-macro-character #\! (lambda (p c) (read-delimited-list #\$ p)))
! import ! srfi :1 $ $
! fold ! lambda ! x y $ ! print ! - x 1 $ "!= " y $ ! * x y $ $ 1
  ! iota ! string->number ! cadr ! command-line $ $ $ 2 $ $
まぁ、ある意味当たり前だが、括弧8個でいける。
set-macro-characterは本来は(sagittarius reader)をインポートして使うべきだが気にしない。
しかし、これ見てSchemeと思う人はおらんだろうなぁ。

リーダーマクロが動いた

まだ、あまりテストしていないが、簡単なリーダーマクロが動いた。
とりあえず当初の目的の通り正規表現を#/regex/と書ける様にしてみた。こんな感じ。
#<(sagittarius regex)
(import (sagittarius regex))
(define rx #/\w+/)
(print (regex-replace-all rx "abcdef@abcdef" "**$0**"))
もちろん#/regex/ixumsのようにも書ける。
汚いなぁと思うのは#<(ライブラリ)のように書かないとリーダーマクロがインポートされない部分。上記のようなプログラムなら(import)がやっても一緒なのだが、ライブラリが問題になってくるので、こんな風にした。
また、loadしたファイルの影響を受けると意味が分からなくなるので影響範囲はファイル単位になっている。

括弧ゴルフに勝つるツールが手に入った(違

2011-12-23

Linuxでコンパイルさせるためのメモ

tarボールでコンパイルさせるテストの一環。
そのうちソースに反映させるが、忘れないようにメモしておこう。

xubuntu 10.xx(細かいバージョン忘れた)ではapt-getでインストールできるcmakeのバージョンが2.8.3だったので、CMakeLists.txtの先頭行にあるバージョンを2.8.3にしてテスト。

手直しが必要だったファイル:
  • library.c
  • core.c 
  • transcoder.c
  • system.c
  • load.c
  • test-lib.c
  • src/CMakeLists.txt
  • ext/ffi/CMakeLists.txt
library.cとsystem.cはミューテックスの初期化問題。まじめにInit関数でやりましょう。特にlibrary.cはInit関数がないので作成して、core.cで呼ぶ必要がある。
system.cは<io.h>がないって言われたのと、environがないって言われた。<io.h>はcmakeを走らせる際にチェックを追加する。environはどうしよう?見つからない理由が分からない。とりあえず通した際にはextern char **environをつけた。
transcoder.cはcodec内で使ってる名前で怒られた。その名もputcとgetc。こいつらマクロなんだ。知らなかった。あればundefするように変更。どうせ中では使ってないし。ってか、こんな極悪なマクロ作るなよ・・・mix、max並みにひでぇ・・・
test-lib.cはuintptr_tがないと怒られた。&t;stdint.h>をインクルードして解決。
src/CMakeLists.txtはpthreadとdlをターゲットリンクに追加。
ext/ffi/CMakeLists.txtはapt-getでlibffiをインストールしたので、ターゲット名が違った。この辺Cygwin版と比較する必要があるなぁ。

以上をなおしたらコンパイルが通った。意外と自動ダウンロード機能も働いていて、BoehmGCは勝手にダウンロードしてコンパイルしていた。(zlibは既にいたのでそのまま使用していたが)
ユニットテストはなんと肝心なrun-test.scmがtarボールに入っていなかった。とりあえずリポジトリからファイルをダウンロードして走らせる(汗。自宅のxubuntuは非常に非力なマシンで動いているので初回テストはガリガリと音を立てていたが(メモリが少ないのよ)、オールクリア。キャッシュテスト用に再度走らせても問題なかった。大枠の出来は割といい感じみたいだ。
ドキュメントの生成も(テストが通ったので当たり前だが)動いている。
まっさらな状態で一応全部いけるということが分かったのは大きい。

それにしても、非力なマシンにもかかわらずコンパイル時間がCygwinでやるより早かった。VCでnmakeを使ったときにも感じていたが、GCCが遅いのだとばかり思っていた。

バージョン0.2.3リリース

今までextディレクトリをtarボールに入れ忘れていたということに気づいて、今回からはそれらが入ってきます。(ということは今までのtarボールってコンパイルすらできなかったということだろうか・・・試してないからなぁ。今後は試すようにしよう。)

今回のリリースは後の拡張に備えたメンテナンスリリースです。

修正された不具合:
  • ライブラリインラインでマーキングミスがあったのが修正されました
  • bitwise-first-set-bitにbignumを与えた際、不正な値を返すことがあった不具合が修正されました
  • renameエクスポートが正しく動作していない不具合が修正されました
改善された動作
  • 文字セットが組み込みになりました
  • gcdにbignumを与えた際のパフォーマンスが改善されました。メモリの使用量が大幅に減っているはずです
  • 正規表現ライブラリが新たに書き直されました。単純な正規表現でかつ巨大なテキストに対してのマッチングもしくは文字列置換であれば以前のものより高速に動作することが期待できます
新たに追加されたライブラリ
  • パフォーマンス測定用ライブラリ(time)が追加されました。現在のところtimeマクロのみエクスポートされています
Windowsバイナリでテストケースを走らせると失敗するテストが2つあります。base64ライブラリのテストとmimeライブラリのテストです。どちらのライブラリもドキュメント化されていないのですが、使用する際は注意してください。

次はリーダーマクロだ!ほぼ正規表現のためだけに入れるといっても過言ではないが、まぁ気にしない。

根本的な解決ではないが

RSA鍵の作成時に素数チェックにgcdを使用していて、Bignumのgcdが非常にナイーブな実装だったため大量のメモリを使用していた。そこで、binary GCDを実装して、メモリの割り当てが最大で4回になるように実装しなおした。そしたら、前述の不具合はとりあえずなりを潜めたのであった。
(あんまり高速化にはなっていないっぽい。512ビットの鍵ペアを作るのに2秒かかる[Core2Duo 3GHz]。Javaでは109ミリセコンドという、20分の1の時間で生成された。う~む)

Windows版のSagittariusでもそれなりにいけるようになってきたような気はするが、テストを走らせると失敗するケースが1つ増えた。正規表現ライブラリを置き換えたからかもしれない。かなりテストを書いたがまだカバーしきれてないらしい。でもテスト外で同じ正規表現、同じ文字列でマッチさせるときっちりマッチするんだよなぁ。メモリ系だろうか、また・・・。Windows版だけというのがまた痛い。メイン環境じゃないからデバッグがしづらい・・・

とりあえず、「よきに計らえ」と勝手に言い聞かせて0.2.3をリリースしてしまおう。

2011-12-22

バグの原因究明

Sagittariusにはドキュメント化されていないライブラリが結構ある。理由はさまざまで、APIが固定されていないとか、近い将来変更になるのでその後とか、バグが取れてないとか、まぁいろいろだ。
その中の「バグが取れていない」の代表格暗号化ライブラリでどこに不具合があるのかがようやく分かった。
結論を言えば、メモリ割り当ての際にオーバーラップして割り当てているせいで、メモリ破壊を起こしているというものだ。
原因はおそらく2つに分けられるだろうが、1つはBoehmGCがマークミスを起こしている。これは回避しようがないので、あきらめるしかない。もう一つは何らかの理由により、割り当てたメモリが使われていないという状態になり、GCによって回収されている(一緒くさいな・・・)。とりあえず前者っぽい挙動をしている。なぜだ?

今回はどうやって直すかというのではなく、どうやって探したかをメモしておく。場所を特定するのに非常に面倒なバグだったので。

起きた環境:
  • VCでコンパイルしたバイナリ
  • 自宅ノートPCのCygwinでコンパイルしたバイナリ
職場のPCでは起きないという隠密バグ(職場もCygwin)。BoehmGCのコンパイル時フラグかな?
使用したツール:
  • WinDbg
  • GDB
NMakeを使っているので、VC++ Expressではデバッグできなかった(評価版なのでプロセスアタッチできない)。
デバッグ方法:
WinDbgでウォッチ式を指定。地道に起きるまでステップ実行(涙)。WinDbgではウォッチ式をしていしても、人の目で監視しないとだめだった。面倒すぎ。
ある程度特定したのちに、自宅PCのGDBでデバッグ。何が壊れているのか分かっているので、ブレークポイントでその値が設定される場所で停めて、アドレスを確認。以下のコマンドを打つ。

watch *0x{上記で調べたアドレス}
最初、丁寧にキャストして実行したらGDBが終わらなかった。キャストせずに上記のように打つとハードウェアウォッチポイントになるらしく、実行がすごく速かった。っで、たどり着いた先はBoehmGCのmalloc。。。どうしろと?
さて、解決方法でも考えるか・・・

2011-12-20

ベンチマークとって見た

新正規表現ライブラリのテストを書いているのだが、どの程度速く(もしくは遅く)なったのか知りたかったので、比較してみた。
コードは以下
(add-dynamic-load-path "./build")
(add-load-path "./sitelib")
(load-dynamic-library "sagittarius--regex2")
(load-dynamic-library "sagittarius--regex")
(import (rnrs)
 (time)
 (srfi :13) (srfi :1))

(define bench
  '(begin
     (define-syntax bench-regex
       (syntax-rules ()
  ((_)
   (begin
     (define rx
       (compile-regex "[-_.0-9A-Za-z]+@[-_0-9A-Za-z]+[-_.0-9A-Za-z]+" 0))
     (define (repeat s c) (string-concatenate (make-list c s)))
     (define s (repeat "abcdefgh" 500))
     (define m (regex-matcher rx s))
     (define times 20)
     (time (do ((i 0 (+ i 1))
         (r (regex-replace-all m " ")
     (regex-replace-all m " ")))
        ((= i times) r)))))))
     (bench-regex)))

(let ((args (command-line)))
  (if (= (length args) 2)
      (cond ((string=? (cadr args) "old")
      (eval bench
     (environment '(sagittarius regex impl) 'user)))
     ((string=? (cadr args) "new")
      (eval bench
     (environment '(sagittarius regex2 impl) 'user)))
     (else 
      (error 'command-line "unknown option")))
      (print "usage: test2.scm old|new")))
で、結果。
$ time ./build/sash -D./build test2.scm old

;;  9.964000 real    9.890000 user    0.000000 sys
./build/sash -D./build test2.scm old  10.06s user 0.03s system 99% cpu 10.176 total
$ time ./build/sash -D./build test2.scm new

;;  0.013000 real    0.015000 user    0.000000 sys
./build/sash -D./build test2.scm new  0.19s user 0.00s system 96% cpu 0.193 total
Pikeさんパネェっす。
別にこのパターンに特化しているわけではないのだが、Perl拡張正規表現が入ってくると別の話になる。それは一つ前のエントリで書いた通り、VMが遅いけど多機能モードに移行するので以前のものより遅くなる可能性が高い。(というか、多分遅くなる)
ただ、個人的に(後方参照はかなり便利だからちょっと考え物だが)先読み、後読み系やpossessiveマッチはあまり使わないので気にしていない。便利なんだろうけど、そんな込み入った正規表現書かないという理由で。

テストケース整備して、APIを以前のものと同じにしたら0.2.3をリリースしよう。

2011-12-19

ハイブリッドVM(正規表現)

正規表現を書き書き直している最中、RE1とRE2を参考にしたPikeVMでは肯定先読み系はおろかpossessiveマッチさえも実装が困難だということに気づいた。
そこでとりあえず普通に再帰を使って書いてみたら恐ろしく遅かった。
どうしたらいいかなぁと電車の中で考えていたら、「ハイブリッドにしちまえよ」という悪魔のささやきが聞こえたのでやってみた。

どうしたか?
拡張正規表現(ここでは上記の2つ+バックリファレンスを指します)を除いた単純な正規表現のみで記述されたパターンはPikeVMで動かし、えらいごてごてした正規表現は再帰を使ったVMで動かしてみた。
これやるとおそらくpossessiveマッチで書いた方が遅いという不思議現象が起きるがそれは置いておいて、後読み(と後方参照もかな?)を除いた210個の単体テストが通った。遅いVMだと異常に実装が楽だったが、涙が出るほど遅く、PikeVMでは速いけどバックトラック系の処理が書けないというジレンマをまぁ使えそうかなぁと思える程度には解消した気がする。
(それでもJavaから移植したコードの方がまだ多少速い・・・まぁ最適化ほとんどしてないからある意味当たり前なんだけど)

後は後読みと細かいフラグの部分を実装して、APIを実装したら一応完成か。クリスマスまでに間に合うだろうか?

2011-12-16

ふと、テレビを見ていて思ったこと

標題に似合わず英語関連です。

文自体は忘れたが、その中にあった単語「labour」を見てふと思ったこと。
そういえば、上記の単語は自然な感じだが、「labor」と書かれると不自然な感じがする。いや、単に英語と米語の違い名だけで意味は一緒なのだが。っでなんとなく自然に感じるつづりと不自然感じがするつづりを並べてみた。
ちょっとしたつづりの比較
英語米語自然だと感じる方
colourcolorcolor
labourlaborlabour
behaviourbehavior両方OK
favourfavor両方OK
favouritefavoritefavourite
centrecentercenter
theatretheater両方OK
とりあえず思いついたのがこんな感じだった。不思議と「ou」になるのが自然と感じるみたいだが、さすがに「color」はこっちのが自然だ。「center」もまぁどちらかと言えばという感じだが、職業柄どうしてもこっちの綴りになる感じ。そのため、「theatre」はこっちの方が自然。(というか街中で見るのはこっちか、bioscoopeだし)
labourは多分カナダにいたときに見た「labour day」が印象に残っているのだろう。
あと何があるだろう?「z」と「s」かな「analyse」とか。うっかり「s」で書いて、Google先生に尋ねたりしてる。
ヨーロッパなのでCMとか英語よりになるんだろう。実際そうだと感じるし。

どうでも話だった。
そういえば、中学、高校の英語のテストで「centre」って書いたら○もらえるのかね?「favourite」はいけると思うけど、どうなんだろう?

2011-12-15

正規表現実装中

ぶっちゃけ行き詰ったのでちょっと問題点の洗い出し。

出来てそうなこと
  • greedyマッチ
  • non-greedyマッチ
  • スタートとエンドアンカー
  • 単語境界
  • グループ(キャプチャリングとそうじゃないの含む)
  • 文字クラス
出来がやばそうなの
  • 肯定、否定先読み及び後読み
  • possessiveマッチ
やばそうなのもある程度は動いてるんだけど、パターンによっては簡単に無限ループに入る。
例えばこんなパターン
\D(?!123)
っで、"ABC123"を与えた場合、文字「C」にマッチしなければいけないが、マッチしない。また、パターンが
\D*(?!123)
になると無限ループする。(ほとんど出来て無いじゃん!)
原因は幅0を実装しているところにあって、2つ目のパターンだと、文字「A」は「\D」と否定先読みの両方を見る。っで、否定先読み(肯定でも)の条件にマッチすると、次の文字に行かずその場にとどまる(幅0の実装)。そうすると、結局文字列"ABCD123"の先頭から同じパターンを繰り返すので無限ループ突入となる。
っと、ここまで書いてちょっと解決案っぽいのが思いついた。要するに先にマッチしたものがあった場合にアサーションに突入しなければいいのではないだろうか?ちょっと試してみよう。

2011-12-12

ジョークプログラム(sleep sort)

sleep sortなるものを実装してみた。
元ネタはここGenius sorting algorithm: Sleep sort
消えてると寂しいので一応引用。
Genius sorting algorithm: Sleep sort
1 Name: Anonymous : 2011-01-20 12:22
    Man, am I a genius. Check out this sorting algorithm I just invented

    #!/bin/bash
    function f() {
        sleep "$1"
        echo "$1"
    }
    while [ -n "$1" ]
    do
        f "$1" &
        shift
    done
    wait

    example usage:
    ./sleepsort.bash 5 3 6 3 6 3 1 4 7
2 Name: Anonymous : 2011-01-20 12:27
    >>1
    Oh god, it works.

    But I don't like to wait 218382 seconds to sort '(0 218382)
3 Name: Anonymous : 2011-01-20 12:31
    >>2
    yes the worst case is very big
まぁ、要素ごとにスレッドを止めて終わった順に値を表示するだけ。
Sagittariusで書いてみた。append!が破壊的かつSRFI-18をサポートしてる処理系なら何でもいけるはず・・・
(library (sleep-sort)
    (export sleep-sort)
    (import (rnrs) 
            (srfi :1)
            (srfi :18))
  (define (sleep-sort lst)
    (let* ((new (list '()))
           (threads (map (lambda (e)
                           (unless (integer? e)
                             (assertion-violation 'sleep-sort
                                                  "integer required but got" e))
                           (make-thread (lambda ()
                                          (thread-sleep! e)
                                          (append! new (list e))
                                          e)))
                         lst))
           (r (map thread-start! threads)))
      (map thread-join! r)
      (cdr new))))
こんな感じで使う
(import (sleep-sort))
(print (sleep-sort '(5 4 6 2 8 9)))
;; => (2 4 5 6 8 9)
上記のコメントにもある通り、最悪時間(というか計算時間?)は要素内の最大値になるので、馬鹿でかい数値だと10分くらい返ってこないとか普通にありえるので要注意。(ソートが終わらないから仕事ができないという言い訳にはなるけどw)

追記:
びっくりするくらい2番煎じだった件・・・ scheme(gauche)でもsleep-sort

英語に対する感覚

前に英語で書いた記事にコメントが付いていた(スパム扱いされていたので気づくのに遅れた)。
これはそのコメントを読んでちょっと気になったことについて。

前置きとして、批判的な意味合いはまったく無く、コメントやご指摘がいただけるのは非常にうれしいことだと考えています。もしここから以下を読んで不快に思われたらごめんなさい。ということで一応分けてみる。やたら長くなったし。


2011-12-11

Inside of Sagittarius: Library system

I am not sure whether somebody is interested in this topic or not. However if there is someone who is hesitating to use Sagittarius because he/she does not know about inside. (Well, I just wanted to write something about Sagittarius in English, sorry)

The reason why I am writing this article is Sagittarius has a little bit different library system comparing with Ypsilon and mosh. (Sorry, I don't know about other implementation) Those two implementations does not have real library system, as far as I understood it has more like just alpha-conversion. So you can not operate or explicitly call any library with it. On Sagittarius, however, libraries are also a first class object. So you can actually do something with it. (I have no intention to make its APIs public, though). Because of this, Sagittarius has sort of namespace. (The same symbol can be bind to different values in different libraries).

What is the good things of it? Unfortunately, I can only say one good thing with it which you can re-define existing value somewhere in the library somebody wrote. So you can even patch the libraries which is written in C. Well, this is actually not so secure, however it is very convenient for debugging. (I used this behaviour to debug macro expansion.)

How is it implemented? It is actually really simple. The VM has library table which is created in Scheme or C and hold it to make sure no duplicated library exists. And library itself has a hashtable and some meta information. The hashtable's key is symbol and value is gloc. Gloc is sort of handle for bindings.

What is the *bad* thing of it? Well, I don't like to write this answer but every implementation have good/bad things and user must know it. Because of this library behaviour, Sagittarius can not have explicit macro expansion phase, so all for import keyword will be ignored. And because of this, (could be because of my insufficient skill), Sagittarius' syntax-case can not compromise a few R6RS requirements.

Sagittarius is still under developing however it has already a lot of useful libraries (maybe not documented yet...). If you like the idea and want to try R6RS implementation, why don't you try it?

2011-12-08

コードをいじっていない

一応、1週間の休暇中でコードを触らないと決めたので触っていないのだが、アイデアは出そうなので取り留めないことをメモしておこう。

正規表現書き直しについて
マッチが既存のものより3倍程度遅いが、これはひょっとしたらマッチさせるたびにメモリの割り当てが3回発生してるからかもしれない。なので、現状マッチさせる際に作成しているコンテキストをマッチャー作成時に初期化して再利用したら高速化されるかもしれない。これでなお遅かったらなんだろう?
Possesiveマッチとか後方参照とかどうしよう?RE2はサポートしてないんだよね。パーサーはCL-PPCREを参考にしたので、その辺対応してるのに、VMは対応(まだ、だといいな)してない。考えないと。

リーダーマクロについて
これは実装手順になっていくのかな?現状ではまぁ普通にスイッチ文で一文字ずつ見ている。次のリリースもしくはその次位には細かく分けられたリーダーを用意して都度プロシージャーを呼び出すようにする。ただし、Cで実装されたものを単純にapplyすると遅そうなので、それは直接呼び出すようにする(引数さえ調節可能、ってかVMはそうしてるし)。その後、リーダーマクロ用のテーブルにマクロのセットを足してディスパッチするようにしてやる。ユーザー定義のリーダーマクロはそこができてから実装するようにする。多分、文字の登録もしくはディスパッチャ(2文字)の登録になるはず。CLの実装も確認しておきたい。xyzzyのソースを読む必要があるか?
(まずはCLのリーダーマクロをいじってみろという話もあるが・・・)

CLOSについて
これは0.3.0くらいに入れたい機能だが、実装方針をとりあえず立てておきたい。ソースが結構大きくなっているので、少しずつ置き換えるというのが難しいかもしれないが、最初は即値クラスから実装(fixnum、文字、boolean、etc)。一気に置き換えるなら現状のタグを消してコンパイルかけて一つずつつぶしていくという地味な作業になるだろうか?気になるのはタグの11ビット以降を利用しているもの(文字列とか)。別にフラグを構造体に持たせる必要がでるのか、現状のようにヘッダー内でなんとかしてしまうか悩むところ。
クラス階層として、文字列、ベクタ、バイトベクタをシーケンスクラスのサブクラスにしようかはちょっと悩むところだが、ハッシュテーブルとツリーマップはディクショナリクラスのサブクラスにしたいところ。
総称関数は多分後回しにできるので、先にクラス構造を入れてしまいたい。
まずはTinyCLOSのソースを熟読するところから始める必要はあるだろう。

もし何方かSagittariusを使っていて、こんな機能がほしいってのがあったら是非教えてほしいですm(_ _)m

2011-12-05

Reader macro preparation

Since I want to add CL like reader macro to Sagittarius, I have been thinking how. I think I had a solution for it so I'm going to memorise it.
Since R7RS draft has been released 4 times and it has different reader macro for bytevector (blob in R7RS or also bytevector?), I need to switch readers between R6RS and R7RS. By default, it can be both, but if user (for now only me...) explicitly specified the mode with shabang #!r6rs or #!r7rs, it should enable or disable some R6RS or R7RS specific reader macro. Well, it is actually easy to just switch with current solution (currently I just see the flag of it and check). But it's not so smart when R8RS or R9RS appears.
So, I'm thinking to add reader macro sets to VM and for future even libraries. The concept is really simple, I just need predefine reader macros for R6RS and R7RS it can be shared its implementations and when #!r6rs or #!r7rs appears switch the set. For this purpose, this behaviour must be per file like current shabang and by default it should have everything (just my preference)
How to do it? The point will be 2 or more letters reader macro such as #vu8(...) or #u8(...). I am thinking I will add 2 sets to VM. One is one letter reader macro and other one is 2 letters reader macro and 2 letters are high priority (or else bytevectors will be invalid vector syntax ...)
Well, I wrote about reader macro however first of all I need to finish replacing regular expression library...

LA行ってきた

今回はバカンスではなく、仕事の面接ということでダウンタウンがメインだった。面接の結果はまだ出ていなく、ボールは向こうが持っている状態。ただ、ボールがもしこっちに来た際には決断をしなければならない。いく前は割りとLAに行こうかなと思っていたのだが、今は揺れている感じ。
いくつか理由がある。良いところと悪いところ両方。少し頭の中をまとめていこう。

良い点
  • まず間違いなく給料があがる。それも下手したら3倍くらい。
  • うちの彼女がアメリカに行きたがっている(NYCなので東海岸だが・・・)
  • ビザを出してくれるアメリカの企業はほとんどないので、次はないかも
悪い点
  • アメリカにいるのに日系企業で日本のコミュニティにいたら、なんか違う。
  • 生活面ががらりと変わる。特に気候とか。夏場40度もあるって聞いたから多分融ける。
  • RX-8は諦める必要がある。(持っていくのが不可能に近い)
  • IT系でも今やってる分野からかなり離れるので次を考えたときに不安。
  • あのLA訛は慣れるのに時間掛かりそう。
大きな部分を占めている順に書いてみた。悪い点が多いのだが、よい点の一番上はかなりでかい。悪い点の下2つは割りとどうでもいいしw
良い悪い関係なく揺れる点ももちろんいくつかあって、それらも含めて考えないといけない。正直人生の岐路としてはかなり大きいので、ボールがこっちの来ないまま「あの時は残念だったね」なんて言っていた方が楽かなぁとも思ったりする。優柔不断な性格には結構きつい・・・

2011-12-01

LAに到着

着陸アプローチが2回あったり、空港が停電してたりとあんまりろくなことがなかったが(機内食のチキンカレーは旨かったか)、無事LAに到着。
思っていた100倍でかい街でちょっとうろたえていたり。あまりにでかすぎて既にオランダが恋しいというチキン野郎。

何故ここにいるのか、(しかも独りで)、実は面接を受けに来ているのです。そう、ひょっとしたら(また)移住するかもしれない。オランダ気に入ってるので、給料の額面とか次第ではあるけど。(まだ決まってない)
自分自身こんなに国を転々とするとは夢にも思っていなかった。本当どこでこんなイベントフラグ立てるんだろう?
どうでもいいが、LAの人の英語が聞き取りずらい・・・オランダ訛に慣れすぎたか・・・

2011-11-29

ちょっとひどすぎだろこれ?

橋下知事が高校生をフルボッコwwwwwww
上記のサイトにあった動画を見た。ひどすぎというのは知事ではなくて、高校生の方。
討論になってない。というか嘆願にすらなってない。

というだけでは自分も同類なので、まずは自分がどちら側か。もちろん知事側。
理由、僕は大学受験の際に不景気のあおりで傾きかけていた親の事業のため、母親から「お前だけは国公立に行ってくれ」と言われたので。
この高校生たちに言いたいこと。中学のときに勉強しなかったの?それとも別の理由で私学に行ったの?学力が優秀なら奨学金制度もあると思うけど、それは活用しないの?etc.

と、これだけだと面白くないので、高校生側からなんとか議論に持っていけないかとも考えてみた。
大阪の受験事情を知らないので、僕が高校受験をした際の愛知の事情で。
愛知県は当時A日程、B日程と分かれていて、もちろん両方受けることができる。ただ、進学校を狙って両方とも自分のレベルより少し高い高校を受けた際に、両方とも落ちるということはままある。この辺僕は割りと問題だなぁと思っていて、どうしても滑り止めとして私学を受ける必要があった。(もちろん中学浪人という選択肢もあるはあるが)
僕ならそこを切り口にして、
  • 将来的に○○を専攻したいと思い、その分野に力を入れている公立の進学校を狙ったが、不甲斐なくも両方落ちた
  • 母子家庭で母親の収入だけでは厳しいのを知っていたが、進学校の私立に自分もバイトをして学費を稼ぐからと無理をいって入学
  • そうは言ってもそれだけでは厳しいし、バイトばかりして学業がおろそかになるのも本末転倒なので、補助金も学費の足しにしていた
  • 奨学金は大学の入学費等に当てるため貯金している
という路線で補助金の必要な環境にいることをアピールして、例えば学業の優秀な人には補助金を出して教育に力を入れるよう促すかね。
でも、単に補助金の減額だった上記のようなのは考慮に入ってるかもしれない。全額カットだと議論に余地ありかもしれない。問題は、そこまで考えている高校生には見えなかったのと、話の内容から箸にも棒にも引っかからない成績だったので私学に行ったように見えたので、話に信憑性がでないことか。

2011-11-28

頓珍漢なコメントをしてしまった

えぇ、正直浮かれてました。

事の発端はこちらのブログ
R7RS実装のポイント(改) - .mjtの日記復帰計画
なぜ浮かれたか、Sagittariusの名前が載ってたから。
っで、キーワードのことについて触れてたので、頑張ればポータブルに書ける旨をコメントしたのだが、3回くらい記事を読み返しておかしいことに気づいた。
(コメントを消す機能はないみたいなので、頓珍漢なコメントはインターネットに残り続ける・・・orz)
多分、R6RS処理系全体でポータブルなR7RSのライブラリを書くということなんだと思う。(国語苦手だったんです)
もしそうなら、こんな超マイナー処理系まで考慮に入れていただいて大変ありがたいです。moshを散々disってすいません。でも、moshには負けません(何の勝負?)

こんなとこ読んでないとは思うけど、一応言い訳・・・

2011-11-27

トヨタ「ハチロク」

こんな記事を見つけた
トヨタ「ハチロク」復活へ…来春に200万円台
200万円台といわれると、僕のRX-8(日本にある。売られる前に引き取らねば!)と一緒だわね。まぁ、前半か後半かで大分違うが。(僕のは240万台だったかな?そこから20万値引きがあったけど、諸費用が結構かかった記憶。ブログのどこかに書いたか?)
正直、トヨタがそう好きではないというのを差し引いても、あまり魅力を感じないなぁと思ってしまった。水平対抗なエンジンがいいっていうなら、スバルのインプレッサを買えばいいわけだし、イニシャルDを読んでない20代の若者はハチロクって言われても「何それ?」だろう。
スポーツカー好きな僕としてはメーカーがスポーツカーを作るというのは非常に好ましい状況なのだが、これはどの層をターゲットにしてるのかわからないなぁ。(RX-8のときは4ドアスポーツカーで、多分30代の家族持ちでスポーツカーにもう一度乗りたいという人だったのだろうと思う)
正直今のご時世で2ドアスポーツに200万以上払う人がいるだろうか?マツダのロードスターみたいな「車好きに!」みたいなコンセプトならまだしも、そうは見えないしなぁ。

この辺の意見を見ると、賛否両論だなぁ。まぁ、元が2chなので微妙ではあるが。
下の方みたら、ベースで250万になるとかのレスがある。本当なら正直RX-8より魅力が低いのに価格が上という糞仕様になるなぁ。(多少RX-8贔屓過ぎるか?ロータリーエンジン可愛いよロータリーエンジン)

日本のIT企業とオランダのIT企業の比較

slashdot.jpにこんなのがあった。
日本人プログラマーについての記事が Hacker News で話題になった
元ネタはこっち(英語)
Force Multipliers and Japanese Programmers

要約すると、日本企業は新しいフレームワークを使うことを極端に嫌がるため、生産性を落としているというものだ。
僕が日本のIT企業で働いた経験は(多く見積もっても)4年半なのであまり本質を捉え切れてないかもしれないが、大まかにそうだなぁと思うところが多々あった。スラッシュドットのコメント蘭は特に的を射ていた感がある。
それにプラスしてではないが、自分が感じたオランダ企業との比較をちょっと書いてみようと思う。一つしか知らないのであまり参考にはならないが。

納期を極端に重要視する
日本で働いていた際にどう考えても無理だろうという納期があったが、いわゆるデスマでなんとかした経験がある。その際にプロジェクトマネージャーに「どう考えても間に合わない再スケジュールしてくれ」と頼んだのだが、答えは当然「無理!」だった。
逆にオランダではその辺は割りと柔軟でこちらからあらかじめアラートを挙げると、優先順位の付け直しをしてクライアントとスケジュール調整をしてくれる。

自社製のフレームワークに極端にこだわる
まぁ、これは上記のブログでも言及されていたが、日本では割と元請けのフレームワークの使用を強制される。そのフレームワークが「実際に生産性を向上させるもの」ならいいのだが、4年半(開発者としては2年半)の間にそのような優れたものを見たことがない。おおよそ、「素直にhibernate使えよ」とか(当時なら)「素直にstruts使えよ」というようなものが主だった。個人的にこれらのフレームワークが好きではないのだが(特にspring)、確かに車輪の再開発をする必要がないのでビジネスロジックに集中できる。また、一度これらのフレームワークを習得してしまえば別のプロジェクトでも使えるので習得期間という初期コストを抑えられる。でも、○○社謹製△△フレームワークなんての物の習得がプロジェクト毎に入るんだよね。大抵上記のフレームワークの劣化版かつAPI互換性なしで。まぁ、その期間なにもしなくても金が入るから偽装派遣屋さんには美味しいかもしれないけど。

ユニットテストの概念がない、その為リファクタリングが非常に困難
この辺は今はよく知らないけど、僕が働いていたときはテストといえばテストケースの仕様書があって、人間が手でデータを揃えて都度エビデンスの作成。仕様変更もしくは不具合修正があればやり直し。これが結合テストですらなく単体テストレベルだったから涙が出そうだった。
(じゃあ今テスト駆動でやってるかといえばそうでもないのだが・・・)

PG->SE->PM以外のキャリアパスがない
個人的にはこれは結構問題だと思ってて、それぞれ全然違うものなのにあたかも順当なキャリアパスのように扱っている。例えば日本の求人を見ると、「PG->SEへと着実なスキルアップ」なんて殺し文句をそれこそほぼすべてのSIerの求人でみる。SEというポジションが最早なんなのか分からなくなったけど、SEの先にPMがあるなら、PG->PMになるはずだ。PMってプロジェクトマネージャの略なのでスケジュール管理とクライアントとのミーティングがメインタスクになる。
そうなりたいならいいけど、プログラマからそこに行く道って、大工が保険の営業になるくらい違うと思うのだが、どうしてそれがデフォルトなんだろう?(理由は次の問題で)

PMが最も単価の高い高級職
上も問題の答えだと思う。企業は単価の高い人間を売りたい(IT企業の多くが2次請け=人売りだと仮定)ので、単価の安いPGよりも単価の高いSE、PMを元請けに売りたいわけだ。
でも、これってすごく間違っていて、技術の高いプログラマが育たない、もしくは育っても開発に携わらないということになる。
これはモチベーションの問題だが、PGの単価が安いってことは、がんばっても給料安いのでやる気もでんわね。

思い出せただけでこれだけか。そもそも、文学部出身がPGになるってので間違ってる気がするけど。如何にIT業界(SIerか?)の求める人材がコミュニケーションスキルに偏ってるか分かるところか。

2011-11-24

疎な配列(Sparse Array)

あんまりこれについて書かれてる記事がなかったので書いてみる。
(MathematicaにマニュアルがGoogleでトップにヒットするんだもん)

事の発端
RE2のソースを読んでて、SparseArrayなる入れ物があるのを発見。Sparse Arrayとは何ぞやと思い調べてみた。

分かったこと
タイトル通り、訳としては「疎な配列」。意味は配列自体は巨大なんだけど中身はすっからかんな配列。(実装が腐ってるとそうなる)
ハッシュマップと何が違うの?もともとは行列を扱うのに適したものだったらしい。なのですべての要素に初期値がある。(ハッシュマップにはない)
後、検索、挿入、削除などのアクセスが定数時間(O(1)ってこと?)。イテレーションにかかる時間がO(n)でnは要素数、配列のサイズではない。
普通の配列を使うより高速かつハッシュマップと違ってリサイズの心配がない。(動的な配列ではないた。、実装によると思うが)


何がハッシュマップに比べてよさげか
あくまで配列なので、ハッシュの計算をする必要がない。(RE2のSparseArrayはそうなってる)
RE2の実装ではイテレータはインデックスと値のpairを返す。(多分そうやってO(n)のイテレーションを実現してるのだろう、for(int i = 0; i < size; i++)とは書けないということだね)
リハッシュの心配がないので、メモリの見積もりが聞く。


何が単なる配列よりよさげか
総アクセス時間が要素数に対しての線形になる。(配列のサイズじゃない)

自前で実装するほどのメリットが今のところ見当たらない。結局メモリの節約になるわけでもないし。
あ、まてよ、RE1もRE2もコンパイルされた正規表現のインストラクションの数だけ配列つくってるなぁ。10000以上になってきたらさすがに総アクセス時間がパフォーマンスに影響を与えそうだ。
とりあえず、配列アクセス用のマクロ書いて、パフォーマンスチューニングの段階になったら考えるか。(こういうときC++だとtemplateが使えると便利だよなぁ・・・)

2011-11-23

Inlinable marking

On Sagittarius Scheme, as I wrote before (in Japanese) it has mechanism to inline non exported small procedure and seems constant variable implicitly. Well, it sounds really good, it does optimise like GCC's static functions or static const variables.
However, if it marks wrong way, there is problems. I have introduced define-constant syntax and implicit inliner for non exported constant value since version 0.2.2. The latter one had the problem. The compiler marks some variable which should not be inlinable as inlinable. Let me show my embarrassing staff:
(library (test)
   (export test)
   (import (rnrs))

  (define *inner-value* #f)
  (define *inner-value2* #f)

  (define (test)
    (and (begin (set! *inner-value* #t))
         (begin (set! *inner-value2* '())))
    (display *inner-value*)(display *inner-value2*)(newline))
)
In this case, (I actually did not check if it does mark wrongly or not) *inner-value2* will be marked as inlinable, so the compiler inline it as #f. This is the problem. As you can see, it has to be '().
Inlinable marking is written as conservative as possible. Well, actually it wasn't ...

I was too lazy to open an issue for this on Google code, so I just fixed it.

2011-11-22

俺もアメリカに行くよ

mixiのマイミクが書いた日記の標題をそのままパクリ。
そのままです、アメリカに行きます。3泊4日で。今回はLAです。

期間は11月30日から12月3日まで。何が偶然かと言えば、マイミクは誕生日をアメリカで過ごしたが、どうやら僕もそうなりそうだ。節目の年(と多くの人が考える年齢になる日)をアメリカで過ごすのは何かの暗示だろうか。
まぁ、いろいろ事がうまく(なのか拙くなのか正直自分でも分からん・・・)進むといろんな意味で節目になるだろうなぁとは思っているのだが。

ところで、誰かLAでお勧めがあったら教えて。正直右も左も分からん。
といっても、あんまり身動きが取れる時間がないので手早くいけるお勧めの場所、レストランなどがあるといいなぁ。

2011-11-20

ロードマップを考えてみた

今後のリリースでSagittarius Schemeがどのようになるのかというのを考えてみた。
たいした物ではないし、0.3.0までしか考えてない。
version 0.2.3
  • 組み込み文字セット(完)
  • 正規表現ライブラリの書き直し(in Progress)
    • cl-ppcreの移植
version 0.2.4
  • リーダーマクロの導入
    • 【動機】正規表現を#/regex/と書きたい!
version 0.3.0
  • Tiny CLOSをベースにした組み込みCLOSの導入
    • 【動機】総称関数がほしくなる場面が多々ある
    • 【動機】現状、レコードと公開していない構造体が混在しているのですっきりさせたい
  • 上記をベースにしたレコードの実装
  • (可能なら)VCでの文字列をC++11仕様のU"string"に変更
    • 文字列リテラルをutf-32(ucs4)に統一
    • VCでのコンパイルはCではなくC++になるかもしれない
思ったとおりたいしたものではなかった。もちろんバグフィックスは随時だし、簡単にできそうかつ効果的だなぁと思ったものは実装していくと思う。
なので0.3.0が0.2.4の直ぐ後に来るとは限らないわけだが。(ただCLOSを組み込みにするとなると、結構な修正が入るので、無暗に修正範囲を広げることはしたくないので、多分0.2.4の後は0.3.0になると思うが。もしくはリーダーマクロを0.3.1に回すかもしれないが)
リーダーマクロは実装の目安がある程度あって、試してみたいなぁというのがある。これも内部的に結構いじくることにはなるので、(主にリーダー周りだが)どこで入れようかは実際迷い中。

独自実装を入れすぎだろか?
まぁ、Mostly R6RSと謳っているので問題ないか。ユーザー数1(僕)だし。

2011-11-16

正規表現ライブラリを書き直そう

組み込みの文字セットが完了したので、いよいよ本丸に取り掛かろう。
現在SagittariusではJavaから移植した正規表現を使っている。別にこれで問題はないと言えばないのだが、気になるのはその中で独自のASTを持っていること。
せっかくSchemeなんだしS式でASTを構築したほうがいいんじゃね?とちょっと思えてきた。
なぜそう思ったか?
世の中にはPCREとSREという正規表現のタイプがあるらしい。まぁ、もっとあるだろうが。っで、PCREは超有名なPerlの正規表現。SREはS式で書かれた正規表現らしい。Perl形式の正規表現をSREに置き換えて、ってやれば、PCREもSREも使えて一粒で2度おいしい感じがする。
と、こういうことをやっているのが、irregexというAlex Shinn氏が書いてるScheme用の正規表現ライブラリなわけだ。とりあえず、それを足がかりに文字列->SREなものを作って、ごにょごにょするか、もう少し資料をあさってみるか。(鬼車のソースを眺めてみるのもありか)

2011-11-15

Scheme使いのためのClojure入門

なんてタイトルをつけてみた。別にたいしたことをするわけでもなく、単に文法上の比較というかなんというか。
とりあえず、Clojureを触ってみた感想ではある。
;; 定義
(define hello
 (lambda (name) (string-append "hello, " name)))
;; or
(define (hello2 name)
 (string-append "hello, " name))
;; 定義
(def hello (fn [name] (str "hello, " name)))
;; or
(defn hello2 [name] (str "hello, " name))
特に何も書く必要はないだろうというくらいよく似ている。[]は引数だけど、ベクターのリードマクロでもある。
うわさによるとdefnは構文ではなくマクロだそうだ。 あと、defnはデフォルトでSchemeでいうcase-lambda仕様になっている。
;; 名前付let
(define (factorial n)
  (let loop ((cnt n)
            (acc 1))
    (if (zero? cnt)
        acc
        (loop (- cnt 1) (* acc cnt)))))
;; 名前付let
;; なんてものはないのでloopとrecurを使う
(defn factorial [n]
  (loop [cnt n acc 1]
    (if (zero? cnt)
      acc
      (recur (dec cnt) (* acc cnt)))))
loop構文は多分letのバインド方式だと思う。Clojureではletは括弧が一つでよくて、順に変数名、初期値、以下続くという感じになる。Schemeに慣れているとちょっと混乱しそうになる。
とりあえずこれくらいにしてしまう。本家サイトにドキュメントあるので、興味があればどうぞ。

それはおかしいだろ

マジで言ってるなら人間性を疑うレベルだが。
https://twitter.com/#!/YANA1945/status/136027550081220608
今日の面接。「もし給料が支払われなかったらどうする?」私が必ず訊く質問だ。目をキラキラさせて「構いません!」と叫ぶ人は合格。少しでも戸惑う奴。そんな奴とはプライベートでも口を聞きたくない!さっさと立ち去れ!
「論外ですね」が僕の答えになるだろうなぁ。もしくは何も言わずに立ち去るか。
叫んだ人は奴隷根性丸出しと批判してもいいかもしれない。
業績不振で遅延支払いになるとかだったらまぁ、「理由しだいでは理解します」になるかもしれない。実際、今の会社は今年のベースアップはなしと言われたし、理由もまぁしょうがないかというものだった。
支払われないということは、雇用契約の反故を通り越して「死ね」と言われているのとほぼ同義だと思うので、奴隷なら雇用者の都合で死ねという理念が無ければこの質問は出ないはずだ。

もともとは、
Island Life - 釣りくさいけど
で見つけたものなのだが(べ、別にShiroさんの隠れファンなんかじゃないんだからね!)、豪快に1本釣りされたのかもしれない。
でも、このエントリの追記にツイートした人は面接代行業者とあったので、割とマジなんだろう。整合性も確かにある。
っが、お前同じこと言われたら目をキラキラさせて「構いません!」と叫ぶんだろうな?と問い詰めてやりたい。他のツイートもなんだかキ○ガイじみてるものだったし、まぁ、根性論で走る人なんだろう。
可能な限りお近づきになりたくないタイプの人種だ。

2011-11-14

赤黒木(続)

結局LLRBではなく純正赤黒木を作ることにした。というかJavaのTreeMapの実装をそのまま移植したともいう。
テストができてないが、とりあえずいいだろう。

一つ前の記事で、メモリ効率と書いたが、よく考えればそんなものどうでもよくて、重要な点は順序があることだった。実装してて気づいた。馬鹿か俺は(カカシ風)
この赤黒木はSchemeのAPIにもするつもりではあるが、元々は組み込みの文字セットを実装するためのものである。なので、ハッシュテーブルのようにオーダーがなくなるようなものではなく、データの挿入時にオーダーが保たれるものじゃないと困るわけだ。(範囲等の関係で)

正直赤黒木の中身がどうなっているのかいまいち理解してないが、(2-3-4木を二分木で表現したものということくらいしか・・・)、単に使うだけなら問題あるまい。問題が出たら直せばいいわけだし。
木の回転とバランスが命だということは実装(コピー)してて気づいたが・・・

2011-11-12

赤黒木

(後々の正規表現ライブラリ改善のため)組み込みの文字セットを入れようと考えているのだが、ハッシュテーブルをセットとしてもつより、平衡二分木を持った方がメモリ効率的にいいかなぁと思い、赤黒木を調べ中。(長い)

調べてみると、実装が難儀とあって、LLRBなるものを発見。Javaで200行程度で実装できるらしい。とりあえずこいつを実装して、後から実装を変更するのもありか。
となると、他の二分木も実装(AVL木とか)も試してみたくなるよなぁと思うのが人間で、そうするとインターフェースだけ定義して実装は別にしたい。何を持つべきだろう?
正直、どこまでやるかということになるが、一応Schemeからも実装できるようにしたいなぁと思うと以下のようになるだろうか?
typedef struct tree_map_rec
{
  int type; /* CかSchemeか*/
  union {
    struct {
      int (*insert)(struct tree_map_rec *tree, node_t *node);
      /* so on */
    } c_procs;
    struct {
      /* scheme procs on C object*/
    } scheme_procs;
  } impl;
} tree_map;
問題になりそうなのはnode_tの定義か?まぁ、とりあえずintptr_tの別名にして、実装毎に適当に定義してキャストすればOKだろうか?
あとは、実装ごとにイテレータをどう用意するかとかその辺を煮詰めないとなぁ。この辺C++だともう少し簡単に書けそうだよなぁ。ABIの問題さえなければ・・・

2011-11-11

1年前のネタを拾った

ボーっとどう書く的なネタを探していたら、こんなの発見。

Twitter / ばーるのようなもの: comp.lang.scheme で簡単なリスト操作 ...
comp.lang.scheme で簡単なリスト操作のお題が出ておるな。
っでやってみた。
(import (rnrs) (rnrs mutable-pairs))
(define (acons k v r) (cons (cons k v) r))
(define (process-labeled-list lst)
  (let loop ((lst lst)
      (ans '()))
    (if (null? lst)
 (map cdr (list-sort (lambda (p1 p2) (< (car p1) (car p2)))
       ans))
 (cond ((assv (caar lst) ans)
        => (lambda (slot)
      (set-cdr! slot (append (cdr slot) (cdar lst)))
      (loop (cdr lst) ans)))
       (else
        (loop (cdr lst) (acons (caar lst)
          (cdar lst)
          ans)))))))

(process-labeled-list '((0 a b) (1 c d) (2 e f) (3 g h) (1 i j)
   (2 k l) (4 m n) (2 o p) (4 q r) (5 s t)))
set-cdr!を使うのは卑怯だろうか?
副作用ありだとあんまり関数型っぽくはない気もするが。

他の処理系でも動かすために、aconsを再定義。Sagittariusならなくても動く。というか、import文すら無くてもこれくらいなら動く。

Version 0.2.2リリース

1日寝かせたら不具合を発見したのでそれを直してのリリース。

今回のリリースではコンパイラがさらに定数畳み込みを行うようになりました。また、定数畳み込みを補助する構文としてdefine-constantが正式にサポートされました。
またビルドの際に必要なライブラリがプラットフォームにインストールされていなかった場合、自動的にダウンロードするように改善されました。 ただし、MSVC環境以外ではテストがあまり行われていません。

修正された不具合
  • get-bytevector-n!でcountパラメータがバイトベクターのサイズだった再に&assertionが投げられる不具合が修正されました。
  • Windows版のmake-transcoderがEOLスタイルをlfとして作成する不具合が修正されました。
  • ライブラリのrenameインポートの際に、renameされたものだけをインポートする不具合が修正されました。
  • let*-valuesの右辺値に左辺値が含まれている際にコンパイラがエラーを報告する不具合が修正されました。
  • delete-fileの挙動がR6RSのものと異なっていた不具合が修正されました。
  • ライブラリ内インライン化の際にコンパイラが誤ってインライン可能フラグをつけていた不具合が修正されました。
  •  カスタムポートでclose引数を指定しても呼ばれていなかった不具合が修正されました。
変更された機能
  • パターンマッチライブラリ(match)がAndrew Wright氏のものからAlex Shinn氏のものに変更されました。
  • current-directoryがパラメータ化されました。(current-directory "somewhere")で(set-current-directory "somewhere")と同様の働きをします。これによって(srfi :39)にあるparameterizeとの親和性があがりました。
  • ソケットライブラリ(sagittarius socket)からエクスポートされていた定数が、define-constantで定義されたものと同様の振る舞いをするように変更されました。
新たに追加された機能
  • Zlib圧縮ライブラリ(rfc zlib)が新たに追加されました。
  • プログラム引数処理ライブラリ(srfi :37)が新たにサポートされました。
  • ハッシュテーブルユーティリティ(util hashtables)が新たに追加されました。


個人的に割りといい感じになってきた感がある。正規表現でクラスのサポートをするために文字セットを組み込みにしないと。

2011-11-10

定数畳み込み

コンパイラの最適化をもう一歩進めてみた。
実は以前から構文としてはdefine-constantをサポートしてはいたんだけど、何もしない単なるサポートにしかなっていなかった。
っで、せっかくライブラリのインライン化とかやったので定数も畳み込んでしまおうと思い立ってやってみた。

基本方針は以下の通り。
  • 定数のみ。
  • exportで定義されていない。
  • コンパイラの最適化で定数になるものは含める。例えばこんなの
    (define a (car '(a b c))) ;; コンパイラは'aをaに定義する。
  • define-constantで定義されたものはライブラリ外でも参照する
とりあえず、なんとなく動くようになったっぽい。以下のコードでは定数が畳み込まれていることが確認できた。
(define-constant a (car '(a b c))) ;; carはコンパイル時に計算される(可能なら)

(define (test)
  (print a))
(disasm test)
;; size: 5
;; 0: CONST_PUSH a <-- シンボルaがそのまま渡されている
;; 2: GREF_TAIL_CALL(1) #<identifier print#user(0x5fd1e0)> ;; print
;; 4: RET

(library (inner)
    (export const-value)
    ;; define-constant は(sagittarius)ライブラリにて提供
    (import (sagittarius))
  (define-constant const-value 10)
)

(library (test)
    (export test2)
    (import (rnrs)
     (inner))

  (define a (+ 1 2 3)) ;; a はexportされていない

  (define (test2)
    (display a)
    (display const-value)
    (newline))
)

(import (test))
(disasm test2) 
;; size: 13
;; 0: FRAME 4
;; 2: CONSTI_PUSH(6) <-- 計算された後の定数になっている
;; 3: GREF_CALL(1) #<identifier display#|(test)|(0x73d018)> ;; display
;; 5: FRAME 4
;; 7: CONSTI_PUSH(10) <-- GREF const-valueではない
;; 8: GREF_CALL(1) #<identifier display#|(test)|(0x73efa8)> ;; display
;; 10: GREF_TAIL_CALL(0) #<identifier newline#|(test)|(0x73ef30)> ;; newline
;; 12: RET
ま、まずまずでしょう。Gambitのベンチマークにはなんら影響が出ないところが多少以上に悲しいが。(あれらはR6RSのライブラリを使ってないから、最適化がかからん)
もう少し寝かせてから0.2.2をリリースしよう。

2011-11-09

割と大きめな岐路

このサイズの岐路は3度目なのだが、2度あることはじゃないけど、3度目がきたわけだ。
(まだ、不確かな要素が多いので、歯に衣を着せた物言いだったり)

正直迷ってはいたりするのだが、さてどうしたものか。別に今の位置にそう固執しているわけではないのだが、割と気に入っていたりはするので、迷うわけだ。
う~ん、どうしたものだろう。

2011-11-02

ドキュメント

オープンオフィス(以下OOo) をやめて、RacketのScribbleに乗り換え中。
乗換えと言っても、Racketに付属しているものをそのまま使うのではなく、ドキュメント生成スクリプトも同時に書いている。なので、コンセプトだけを使うといった感じ。
Chibi Schemeに触発された感はあるが。

その際にあんまりうまいこと解決方法が見つからなかったのが以下のセクションを拾って目次に変換する処理。
用件としては、以下のようになっているリストをulとliで作成されたsxmlに変換すること。
((section
  (@ (tag "tag1") (number "1"))
  "Section 1")
 (subsection 
  (@ (tag "tag1.1") (number "1.1"))
  "Subsection 1.1")
 (subsection 
  (@ (tag "tag1.2") (number "1.2"))
  "Subsection 1.2")
 (section
  (@ (tag "tag2") (number "2"))
  "Section 2")
 (subsection 
  (@ (tag "tag2.1") (number "2.1"))
  "Subsection 2.1")
 (subsubsection 
  (@ (tag "tag2.1.1") (number "2.1.1"))
  "Subsection 2.1.1")
 (sub*section 
  (@ (tag "tag2.1.1.1") (number "2.1.1.1"))
  "Subsection 2.1.1.1")
 (section
  (@ (tag "tag3") (number "3"))
  "Section 3"))
期待される出力
(div (@ (id "G137") (class "table-of-contents"))
     (ul (@ (class "section"))
  (li (@ (class "section"))
      (a (@ (href "#tag1"))
  (span (@ (class "section-number")) "1")
  "Section 1")
      (ul (@ (class "sub-section"))
   (li (@ (class "sub-section"))
       (a (@ (href "#tag1.1"))
   (span (@ (class "section-number")) "1.1")
   "Section 1.1"))
   (li (@ (class "sub-section"))
       (a (@ (href "#tag1.2"))
   (span (@ (class "section-number")) "1.2")
   "Section 1.2"))))
  (li (@ (class "section"))
      (a (@ (href "#tag2"))
  (span (@ (class "section-number")) "2")
  "Section 2")
      (ul (@ (class "sub-section"))
   (li (@ (class "sub-section"))
       (a (@ (href "#tag2.1"))
   (span (@ (class "section-number")) "2.1")
   "Section 2.1")
       (ul (@ (class "sub-sub-section"))
    (li (@ (class "sub-sub-section"))
        (a (@ (href "#tag2.1.1"))
    (span (@ (class "section-number"))
          "2.1.1")
    "Section 2.1.1")
        (ul (@ (class "sub-sub-sub-section"))
     (li (@ (class "sub-sub-sub-section"))
         (a (@ (href "#tag2.1.1.1"))
     (span (@ (class "section-number"))
           "2.1.1.1")
     "Section 2.1.1.1"))))))))
  (li (@ (class "section"))
      (a (@ (href "#tag3"))
  (span (@ (class "section-number")) "3")
  "Section 3"))))
単にulとliで構成されたリストにちょっとしたhtmlのメタ情報が入ったものといった感じ。これが結構てこずった。
最終的にはこんな風になったけど、もうちょっといい感じにならないだろうか?
;; sxml toolsをふんだんに使ってます。
(define *section-classes*
  '((section       . "section")
    (subsection    . "sub-section")
    (subsubsection . "sub-sub-section")
    (sub*section   . "sub-sub-sub-section")))

(define (content-list-handler element)
  (define (process contents)
    (define (li-gen content class)
      (let* ((attrs (sxml:attr-list-node content))
      (tag   (cond ((assq 'tag attrs) => cadr)))
      (section (cond ((assq 'number attrs) => cadr)
       (else
        (assertion-violation 'li-gen
        "section is not defined" content)))))
 `((li (@ (class ,class))
       (a (@ (href ,(format "#~a" tag)))
   (span (@ (class "section-number")) ,section)
   ,@(map phase2/dispath (sxml:content content)))))))
    (define (ul-gen class)
      `(ul (@ (class ,class))))
    (define (rec contents generator top)
      (let loop ((contents contents)
   (r top))
 (if (null? contents)
     r
     (let ((content (car contents)))
       (let-values (((class depth) (generator content)))
  (let loop ((i 0)
      (r r))
    (if (= i depth)
        (cond ((and (zero? i) ;; top
      (eq? (car r) 'ul))
        (append! r (li-gen content class)))
       (else
        (let ((tail (car (list-tail r (- (length r) 1)))))
          (cond ((eq? (car tail) 'ul)
          (append! tail (li-gen content class))
          r)
         (else
          (let ((ul (ul-gen class)))
     (append! ul (li-gen content class))
     (if (eq? (car tail) 'li)
         (append! tail (list ul))
         (append! r (list ul)))
     r))))))
        (loop (+ i 1)
       (let((rr (car (list-tail r (- (length r) 1)))))
         (if (eq? (car rr) 'li)
      rr
      (car (list-tail rr (- (length rr) 1))))))))
  (loop (cdr contents) r))))))

    (define (section-generator element)
      (define len (length *section-classes*))
      (define sections (map car *section-classes*))
      (cond ((assq (car element) *section-classes*)
      => (lambda (slot)
    (let ((name (car slot))
   (class (cdr slot)))
      (values class (- len (length (memq name sections)))))))
     (else
      (assertion-violation 'section-generator
      "unknown tag" element))))
    ;; assume first one is section
    (rec contents section-generator (ul-gen "section")))

  (let* ((contents (*table-of-contents*))
  (attr (sxml:attr-list-node element))
  (id   (cond ((and attr (assq 'id attr)) => cadr)
       (else (symbol->string (gensym))))))
    `(div (@ (id ,id)
      (class "table-of-contents"))
   ,(process contents))
    )
  )
リストの作成を破壊的に行っているので、なんとなく反則技を使っている気分。いい点は、*section-classes*に追加のサブセクションを足せば簡単にネストできることか。4つ以上サブセクションが要るドキュメントなんて読みたくないが・・・

2011-10-28

とある面接での質問

つい最近、面接を受けたのだがその際に質問された項目の一つ。 「リストとマップとセットの違いについて説明してください」 この質問を聞いた際に、頭の中で、 「listとmapとset!(これ重要)について説明してください」 と変換したため、何を言っているんだろう?と本気で悩んでしまった。 本来の意味では「コレクションとしての」が接頭辞として付くと分かりやすいのかな? ただ、質問の意図は正直今でも分からず、違いを理解せずに使ってるやつなんているの?と思ってしまう。まぁ、自分の理解が正しいか不安にはなるので、ここで晒してみよう。晒すのが答えなのか、恥なのかは分からないけど。 リスト:要は可変配列、要素は重複を許す。 マップ:キーと値をの対を要素として持つ集合。キーの重複は許されない場合が多い。(許す実装をどっかで見た、気のせいかも) セット:集合。要素の重複を許さない。 順序が保障されるかどうかは実装によるのでどうでもいい。ArrayListなら入れた順番だし、LinkedListなら要素の値で順序が保障される(本当?あんまり使わないから分からん)といった感じ。 これが答えられない、もしくは大きく理解がずれてるとしたらそれはそれで問題な気がする。

2011-10-25

R7RSのドラフト4

45時間前にScheme Working Groupに載ってたので読んでみた。なんだかタイムリーに読んだ気分に。
まぁ大きな点はドラフト3から変わらないだろうと踏んで、モジュールだけを読んでみた。ここがmoduleからdefine-libraryに変わるので。
ぶっちゃけ名前が変わっただけだったので特に特筆すべきところはないかなぁ(まだ、しっかり読んでないけど)
モジュールシステムの項で気になる点:
A library definition takes the following form:
    (define-library <library name>
        <library declaration> ... )
<library name> is a list whose members are identifiers or unsigned exact integers that is used to identify the library uniquely when importing from other programs or libraries. Libraries whose first identifier is scheme are reserved for use by this report and future versions of this report. Libraries whose first identifier is srfi are reserved for libraries implementing Scheme Requests for Implementation.
A <=<library declaration> may be any of:
  • (export <export spec> ... )
  • (import <import set> ... )
  • (begin <command or definition> ... )
  • (include <filename1> <ilename2> ... )
  • (include-ci <filename1> <filename2> ... )
  • (cond-expand <cond-expand clause> ... )
これってこんな風に書けるってこと?
(define-library (test)
  (begin (define a 'a))
  (import (scheme base))
  (export a)
)
リファレンス実装(だと思われる)chibi-schemeで試してみたが、どう動かすのかまったく分からん。 まぁ、この程度の違いならマクロで吸収できるなぁ・・・(いろいろ面倒な部分もあるので)R7RS対応にするかは分からないけど。