2014/08/23
Gaucheでaobench再び
ShoyoさんのAmbient Occlusionベンチマーク、 以前 (5年以上前か!) に.mjtさんのR6RS Scheme移植を元にしてGaucheで走らせてみた ことがあったけど、改めて本家のcコードからGauche向けに移植してみた。git master をチェックアウトすればexamplesの下に入ってる。
https://github.com/shirok/Gauche/blob/master/examples/aobench.scm
手元のマシン (Core i7-3770 3.40GHz) でCバージョンと比較。
| ao.c | 0.74s | (gcc -O2) |
| aobench.scm | 8.57s |
ふむ。約12倍か。悪くない…
というのは、嘘。実はaobench.scmはCPUコアをあるだけ勝手に並列に使うように 書いてあるので、Cはシングルスレッドだがaobench.scmは8スレッド並列だ。
チートなしで勝負すると:
| aobench.scm (シングルスレッド) | 33.2s |
Cの45倍。まあこんなもんか。数値計算中心のコードはやっぱりJITじゃないと難しいかなあ。
(なお、シングルスレッドで走らせるには
環境変数GAUCHE_AVAILABLE_PROCESSORSを1にセットする)
それより8スレッドで4倍弱しか速くなってないのが気になる。 CPU使用率はほぼいっぱいいっぱいなのでmutexで待っているわけでもないとは 思うんだが…
あ、でも8コアってのは物理4コア * Hyperthreadingだったっけ。 FPUは4つしか無いんだから仕方ないかな。 なお4スレッド並列だとこのくらい。
| aobench.scm (4スレッド並列) | 10.1s |
Tags: Programming, Gauche
2014/08/13
R6RSとR7RSのシンボル構文
Keiさん(@tk_riple)とやりとりしてて 思いだしたんだけど、R6RSとR7RSでシンボル中の文字をエスケープする構文に互換性が 無いのだった。
- R6RS
シンボル中に
\xNNN;という形でコードポイントNNNの文字を 埋め込める(桁数は任意)。通常のシンボルで許されない文字を使う時は必ずこの方式で エスケープしなければならない。(string->symbol " ") => \x20;
なお、この表記は数多くのLisp方言の中でもR6RS独自の仕様。 また、この表記だと
(string->symbol "")を表現できない。- R7RS
通常のシンボルで許されない文字を使う場合は、
|で挟んで表記する。 この表記はCommon Lispで使われ、多くのLisp/Scheme実装でも採用されている伝統的なもの。(string->symbol " ") => | |
|の中ではいくつかのバックスラッシュによるエスケープの他、\xNNN;形式の エスケープも使える。こちらはR6RSの表記を取り入れた。(string->symbol " ") => |\x20;| ; これもok
ただし、
|で囲まずにいきなり\x20;とは書けないのでR6RS式で エスケープされたシンボルは読めない。
で、どうしてこうなったんだっけ、という経緯を思い出せなかったのでちょっと探してみた。
SRFI-75
R6RSの、シンボルに特殊文字を含める方法については、 まず議論のために提出されたSRFI-75で検討された (これは元々withdrawされることを前提に、srfiのシステムで議論をしよう、という試み。)
タイトルからもわかるように、シンボルの構文だけでなく拡張文字セットについて、 どう扱うか、また文字、文字列、シンボル内でどう表記するか等を包括的に議論するもの。
で、忘れてたんだけど、この時点ではシンボルは伝統的に | で囲んで
特殊文字を入れるようになってたんだな。あと\xエスケープが固定桁で、
\xNN(2桁), \uNNNN(4桁), \UNNNNNNNN"(8桁)になってた
(以前のGaucheと同じ)。
ちょっとこのsrfiは扱う範囲が広すぎて議論がひどく追いにくいんだけど、この中で
- 「
\x+ 可変長16進数 + デリミタ」にしようぜ
っていう流れができた。なおデリミタが ; になった経緯はいまいちよくわからない。
\x{NNN}とか\x<NNN>とかの案もあった。あと、
;だとエディタが対応するまでコメントとまぎらわしいからデリミタを別の文字に
しようぜっていうもっともな話が出たんだけど尻切れとんぼになってる。
もうひとつ、
|で囲んで中でエスケープっていうのは、文字列が"で囲んで中で エスケープってのと同じだよね。- ってことは結局シンボルと文字列ってinternされてるかないかの違いなんだから シンボルをそんなに特別扱いする必要あるの?
- 微妙に違うエスケープがあるのは綺麗じゃないね (縦棒シンボル内では
|のエスケープが、文字列内では"のエスケープが必要) - いっそシンボルを
#"..."にしちゃったら文字列と同じエスケープが 使えていいんじゃね?
てな具合に自転車置場的に議論が発散しつつ、最終まとめあたりでR6RS編集者が
- シンボルを
|で囲めば空白でも何でも入れられるよ、っていうのは、 かつてのLispに文字列が無くて何でもシンボルでやってた頃に逆行してね?- 識別子に空白を入れたいと思うのは何か間違ってるんじゃ
- 読むときも空白で無意識に識別子を区切っちゃうから紛らわしいよね
- どうしても空白入れたければ
\xNNN;表記があるんだから、 別表記を用意しなくてもいいよね
ってな流れになって、「\xNNN; は採用、縦棒表記は止めるかも」みたいな雰囲気に。
そして実際、リリースされたR6RSドラフトでは縦棒表記が無くなった。
なおこの時点で、R6RS式だと名前が空のシンボルが表記できない、ということは みんな失念していた模様。他のトピックでもさんざん議論しててみんな疲れてたのかね。
R6RS Formal comment
R6RSドラフトの段階でシンボルの字句構文が検討されたのは、 これしか見当たらなかった。
これ、Per Bothnerの直接の提案は、シンボル内で \ で任意の文字を
エスケープ可能にしたらどうか、というもの。例えば
(string->symbol "abc def") => abc\ def
ただ、MLでこれが出たときにJohn Cowanが「|で囲う表記も復活させてほしい」
とコメントしてる。
これに対してR6RSエディタは上記のresolutionのとおり、 「シンボル表記中に空白が入るのは紛らわしい」との理由で却下。
この時も誰も「名前が空のシンボルはどうすんの」と突っ込んでないので見過ごされた模様。
R7RS ticket #304
R7RSはもともと新しいことを決めるよりもデファクトの共通部分を追認するという
基本方針。| で囲むのもデファクトだから入れよう、という話はわりと最初から
あったと思う。
で、当初は | で囲うのとR6RS式と両方サポートしてたんだけど、
途中で「このために処理系拡張で使える文字を二つ (縦棒とバックスラッシュ) 使っちゃうのは
勿体なくない?」という意見が出される。
もともとSchemeは「独自言語作成のベース」という性質も持っていたので、 処理系が独自に拡張できる余地は多い方が良い。縦棒式とR6RS式は (空の名前を除いて)表現力に変わりはないのだから、どっちか一つで良いでしょう、 という流れに。で、どっちを選ぶかといえば 伝統かつより表現力の大きい縦棒だよね、という結論になった。
まあR6RSはたくさんのことを決めようとしすぎて、みんな何をどこまで議論したのか わけわからなくなってた感があるな。
非互換性は問題になる?
で、これがどのくらい問題になるかだけど、
- コードについては、R6RSとR7RSでそれなりに書き分けることになるし、 共通化したればもともと共通部分だけで書かざるを得ないんだから、 シンボル名もエスケープ使わなけりゃいいだけだよね
- データについては、リーダをR6RSとR7RSで分けるしかないね。
- 尤もR7RS(-small)の場合、そもそも処理系がUnicode対応かどうかもわからないので、 「R7RS-smallの範囲内」で完全なポータブルを目指すならasciiの範囲内に留めておくしかない。 R7RS-smallはあくまでベースを提供するもんなんで、より大きな共通仕様が欲しかったら srfiとかで対応すればいいんじゃね、ってなノリ。
- R7RS処理系が独自拡張でR6RS構文を読むことは全くの自由だから、 R6RS式が無視できないくらい流行れば対応してゆくでしょ。 そしたら現実的には問題無くなるだろ。
って感じかなあ。R6RSとR7RSで仕様として目指すものが違うので、 一方の立場でもう一方を判断しようとするとおかしなことになると思う。
Tags: Programming, Scheme, Lisp, R7RS
2014/08/02
ピアノレッスン135回目(終)
今の先生とはこれで最後のレッスン。
- Ginastera: Tres Piezas - 1. Cuyana
- 先週はただ物悲しいだけだったけど、今回は色々な風景が見えた。短い曲の中にたくさんの景色が詰まっている。
- Beethoven: Waldstein 1st mvmt
- 今日の演奏は、ピアノ曲というよりシンフォニーのように聴こえた。Good job.
特に課題を出されるということはなく、ひたすら 自分のやりたい曲を持っていって聴いてもらってヒントを授かる、というスタイルだったけれど、 この3年で「見える風景」がかなり変わったように思う。
Tag: Piano
2014/07/26
ピアノレッスン134回目
- Ginastera: Tres Piezas - 1. Cuyana
- 不協和からの解決が綺麗
- Beethoven: Waldstein 1st mvmt
- ほぼ暗譜。
- 左手旋律で右手が細かく動く時、聴衆も右手に耳がいきがちなので、非常に軽く。特に 第二主題で左に旋律が移るところ。
Tag: Piano
2014/07/23
先ずデータありき
前エントリ「プログラムは書いたとおりに動くのか」について、 一部「ああ、データ構造+アルゴリズム=プログラムってことね」というような反応があったんだけど、ちょっと違う。
プログラマ的視点における「データ構造+アルゴリズム」では、プログラマが問題にふさわしいデータ構造を決めるって意識だと思うんだけど、あのエントリで言いたかったのは、プログラマが考え出す前に既にデータそのものがあるってこと。
もちろん何らかの構造を決めないとコードでは扱えないんで、データ構造は作るんだけど、それは無から自由に作るもんじゃなくて、既にある塊の中にある構造の一面を切り出す、みたいな作業になる。まあ、それが結局モデル化って呼ばれる作業なんだけど、しばしばこのモデル化ってのが、具体的なインスタンスからイデアあるいはアーキタイプを見出す作業のようにとらえられてるんじゃないかって気がする。
目前にある具体的なデータは、ある「元型」が具象化したものだから、その「元型」を見つけましょう、それをクラスなり型なりとして記述しましょう、というアプローチ。
でも現実のプログラムの多くはそうじゃないんじゃないか、ってのが言いたかったこと。現実のデータに「元型」なんてなくて、データはデータとしてごちゃっとそこにある。プログラマが設定するクラスなり型はあくまでその混沌を一つの投影面に射影して何とか扱えるようにした暫定的なもので、別の目的なら全く違った型が見えるかもしれない。でもそれぞれが触るインスタンスは同じ具体物だ。本来の情報の流れはインスタンス→クラス、であって、イデアたるクラスが大元にあってインスタンスを産み出しているわけではない。プログラムコードとしてはクラスからインスタンスを作ってるんだけど、それは便宜上そうしてるだけ、って感覚を主張したかった。
んで、このデータっていうのはプログラムより前からそこに存在するだけでなく、プログラムの都合とは関係なしに変化する。それに伴って構造も変化する。
データ構造が先にありき、の感覚だと、変更を主導するのはプログラマだ。けれど、データが先にあるという感覚だと、データ構造は常に暫定的であり、データが変化したらすいっと構造の方を追従させてゆく必要がある。変化については、能動的なのはデータであり、受動的なのがデータ構造を含めたコードなのだ。
一部のプログラミング言語では、実行中にクラス定義を変えたり、 インスタンスが属するクラスを全く違うものにすげ替えたりできる。 これは静的な検証という観点からは最悪の機能だ。だってT型のデータを受け取って、 それをT型を期待する引数に渡すってコードがあっても、その間にデータ自体の型が S型に変化する可能性があるのだから。
でも、特定の設計の適用範囲よりもデータの方が長生きする、という立場に立った場合、 目前にある混沌としたデータをとりあえず触れる形にしておいて、 必要に応じて表現を動的に変えてゆく、 プログラムコードは常にその時点の暫定版に過ぎない、 という見方も可能なのだ。
(別に静的型をdisってるわけじゃなくて、立場の違いってこと。 なお、上で述べたような「混沌としたデータが、投影法によって違うものに見える」 というのは、型クラスとかtraitのような仕組みと相性が良いと思う。)
Tag: Programming

Comments (0)