&rest 引数の使い方が微妙にわかったので,Lisp の format 形式のメッセージをポップアップダイアログに表示する msgbox API を作ってみた.
(define-cproc msgbox (format:: &rest args) (body " ScmObj os = Scm_MakeOutputStringPort(TRUE); GtkWidget *dialog; Scm_Format(SCM_PORT(os), format, args, FALSE); dialog = gtk_message_dialog_new(GTK_WINDOW(Shiki_EDITOR_WINDOW), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, Scm_GetString(SCM_STRING(Scm_GetOutputString(SCM_PORT(os))))); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); SCM_RESULT = SCM_SYMBOL(SCM_INTERN(\":ok\"));"))
(msgbox "current buffer is ~A." (selected-buffer)) ;; ここで C-j :ok
なぜか xyzzy は返り値に :ok というシンボルを返す (symbolp で確認済み) という仕様だったので,一応再現してみた.まぁ,3 byte だし… (intern とかいろいろコストはかかるけど)
Format が使えるのは,scheme の世界からはすごく便利なんだけど,やっぱり C からは使いにくい.というわけで,C では同名の,printf 形式の可変長引数を取るように定義しなおした方が良いかもしれない.
こうしてみると,実は C API でガリガリ書いた方が,部分式がコンパイルされずに何度も何度も実行時に動的に intern やアロケートなどが繰り返されるため,場合によっては読み込み時にバイトコンパイルされる Scheme よりも遅くなるのかもしれない.
う〜ん,C にもコンパイルタイムマクロが欲しいのう (無理).
gcc とか,まっとうなコンパイラなら,共通する (部分文字列も ?) 文字列定数は,全部コンパイル時にインターンされて静的領域に置かれて共有されるはず.SCM_INTERN_STATIC_CONST とか,なんかそんな感じで何とかならないのかねぇ ? (たぶんならない)
まぁ,そんなに神経質にならなくても,二回目以降は無視できる程度なのかな… (src/symbol.c)
ScmObj Scm_Intern(ScmString *name) { ScmHashEntry *e = Scm_HashTableGet(obtable, SCM_OBJ(name)); if (e) return e->value; else { ScmObj n = Scm_CopyStringWithFlags(name, SCM_STRING_IMMUTABLE, SCM_STRING_IMMUTABLE); ScmSymbol *sym; INITSYM(sym, n); Scm_HashTablePut(obtable, n, SCM_OBJ(sym)); return SCM_OBJ(sym); } }
う〜ん,xyzzy が思いっきり Lisp でエディタの大部分を書いてるのは,やっぱりコンパイル (たぶんバイトコンパイル ?) に強い CL だから,ってのがあるのだろうか ?
よく LL の人とかが,「開発効率の方が重要,本当にクリティカルな部分は C で書けばいいじゃん云々」 みたいなことを言うけど,C で書いたら早くなるってもんでも無いと思う.そこらへん,本当にわかってそういう発言してるのかねぇ ?
# いや,速度を気にするような人は,そもそも LL なんて使ってないよな,普通.すいませんでした.以下全部ヨタです.
というか,むしろ C って,言語仕様的には,一番コンパイルには向いてない言語なんじゃないか ?
抽象度も中途半端だし.移植性にしろ,マシンへの近さにしろ,非常にどっちつかずで中途半端.そのせいで autotools みたいな,バッドノウハウがバッドノウハウを呼ぶという悲惨な事態が.そのくせ処理系依存のインラインアセンブラ使わないと,肝心なことは何もできないし.
なんたって,(言語仕様的には) 入出力すらライブラリなんだから.コンパイラは預り知らぬブラックボックスの領域に行っちゃう.
まぁ,gcc なんかだと,たとえば printf あたりは全部ビルトインで持ってて,型チェックやフォーマットの中身のコンパイルみたいなことも一応はやってくれるけど.それは非常に限定された形に過ぎない.
その点 CL なんかは,あの莫大なライブラリ全てが言語仕様の範疇だから,原理的にはありとあらゆる部分にコンパイラによる最適化がかかる可能性が生まれてくる.それこそ静的に確定してる正規表現の中身のネイティブコンパイルまで.
現時点で,そこまでできるマンパワーと力強い (ダーティな) 言語仕様を持った言語ってのは,おそらく Common Lisp と C++ しか無い (いや,ML もポテンシャルは凄そうだけど… いかんせん,アカデミックオンリーだからなぁ.企業のマンパワーが足りない気が) と思う.
いや,確かに 80:20 の法則を考えれば,そんなことに拘るのは無意味というのは,全くの正論なんですけど.
普段はダラダラインタプリタとかで Edit-Compile-Testループを素早く何度も何度も回して開発効率を上げられるし,いざとなったら,コンパイラに本気出してもらって,システム全体をまるごと 3 日 3 晩くらいかけて極限まで最適化することもできる.そんな言語,あったら良いと思わないかい ? (Joel 口調)
ちょっと書きやすかったり読みやすかったりするけど,ちょっとシステムが大きくなると全体を書き直さないと使い者にならなくなるような,15 分だけ時代を先取りした言語 では,オモチャは書けても,本物のシステムなんて書けっこないし,そもそも書かれないだろう. そういう意味で,僕は (少なくとも現在の) LL に未来は無い,という持論があったり.
# いや,もちろん,小粋な web API をちょちょいと使って,マッシュアップとかハイカラな言葉を並べて 30 年前の技術を飾り立てるのがアナタの 「未来」 だって言うならば,話は別だけど.
とかいう話はどうでも良いな.
う〜ん,なんの話だっけ.
そうそう,gauche にもバイトコードコンパイルが欲しいのう.という話だった (そうだっけ ?
まぁ,gauche の目的を考えれば,それはオカド違いな願望なんだろうね.
UNIX と C ってのは,やっぱり最悪のコンピュータウィルスだな.この 2 老害のせいで,計算機科学の発達は 20 年遅れた.こいつらのバッドノウハウにそそぎこまれた,莫大な量の不毛なマンパワーが,もしもっと他のことに正しく向けられていたら… (C はさらに, C++ という素晴らしい後継者にも恵まれたしね)
とか,たまには暴言吐いてみる (笑)
■[C]Cが使われる理由
(via ときどきの雑記帖 リターンズ ■_ 自分で自分を記述する)
# 2006/12/14 追記 : なにやらいろいろなところからリンクして頂いているようなので,遅ればせながら補足.上記は私のオリジナルではなく,The Rise of ``Worse is Better'' 「 Unix and C are the ultimate computer viruses.」 が元ネタです.念のため.
まぁ,いけるところまで gauche と C でがんばろう.どうしても速度や開発効率が気になってきたら,ネイティブコンパイル可能な Common Lisp 処理系も考えるかもしれない.
ただ,現状では,utf8 がそれなりに扱えるのは,バイトコンパイラの clisp ぐらいなんだよなぁ.たぶん.cmucl とかだったら,むしろ全部 CL で書いても良いかもしれないんだけど.xyzzy との親和性も高そうなのに.おしい.
# ついでに追記.SBCL という CMUCL のブランチは,Unicode を扱えます.ただ,CL から gtk を使うやり方がよくわからなかった… wxCL も微妙だったし.
なんかエディタと全然関係無い話になってしまった… orz
いちおう MinGW で出た警告は直したつもり.あと,たぶん charconv がコケても,システムロケール (Windows なら,たぶん sjis.Linux とかなら,だいたい euc-jp ?) と UTF8 の文章ならば,たぶんなんとかなるはず.
# 今 Windows 環境が無いからニントモカントモ… あと,真面目にエラー処理を書くのは,0.8.8 以降に上げてからだと思う.まだ Debian/testing は 0.8.7.
しっかし,スタブのエラーハンドリングがテキトーすぎるな.
C 言語で定義するから,「未定義」 っていう値が表現できないんだな,これが.
だから,Scm_Error が発動してるのに,一見それっぽい値 (gboolean を返す関数とか) が返ってきたり… いちおう正整数を返すやつとかは,適当に -1 とか返してるけど (そもそも Gtk,なんで明らかに正の数しか取らないところに,いっつも gint なんだ ? 謎過ぎる.なんか内部的には,負の数に特別な意味を持たせてるとか ?).
Lisp だったら,#t でも #f でも無くて,# とか nil とか,ナンカてきとぅーに返しときゃいいんだけど.
いや,面倒くさがらずに,返り値を にしておけば良いのか.自動 Boxing されないから全部手動なのはかなりきついけど.
う〜ん,xyzzy lisp には仕様書とか無いからな.何を返しておけば良いのか良くわからん.
ねむい.そもそも Scheme には,nil って概念無いし (いや,nil はあるけど… 単なるシンボル).
shiki|TB:0|CM:10|
|

▲
| |
|
コメント
|
なぜにバイトコードコンパイル? VM instruction vectorではだめな理由があるのかしらん。
あと、internのオーバヘッドが気になるなら初期化時にinternしてポインタを持っとけば良いでしょう。genstubにもそれを支援する機能があります。 |
|
shiro #-|2006/11/29(水) 04:05 [ 編集 ]
|
msgboxはbuiltinではなくmisc.lで定義されていたりします。 message-boxというbuiltin関数の特殊化でOKしか押せないようにしたので、常に「:ok」が返るようになっているということでしょう。(たぶん) |
|
NANRI #LYu7.Z8o|2006/11/29(水) 07:07 [ 編集 ]
|
おぉ,素晴らしい.そんな機能まであったのですか !! > genstub
ありがとうございます.探してみます.
gauche がいったんバイトコードにコンパイルしてから実行している (いわば JIT ?) ということは知っているのですが,ローディング時のオーバヘッドを減らすために,(emacs みたいに) あらかじめバイトコードにまでコンパイルしておけたら良いなぁ,ということでした (^-^;
# 現時点でも,もしかして普通にできたりしますか ? 不勉強ですいません… |
|
あろは #wNX6xxGw|2006/11/29(水) 10:30 [ 編集 ]
|
なるほど,確かに.よく考えれば,場合分けのためには必ず必要ですよね (汗)
----------------------------------- >> ボタンを押したときの戻り値は、それぞれ以下のとおりです。
:ok [OK] を選択 :cancel [キャンセル] を選択 :yes [はい] を選択 :no [いいえ] を選択 :abort [中止] を選択 :retry [再試行] を選択 :ignore [無視] を選択 ----------------------------------- |
|
あろは #wNX6xxGw|2006/11/29(水) 10:40 [ 編集 ]
|
まず、厳密にはバイトコードじゃありません。何て言うべきだろ。ワードコード?
それから、まだ公式なサポートは無いんですが、コンパイル済のVMインストラクションベクタをダンプしてバイナリにしてロードする機能は動いてます。(そもそもGaucheのコンパイラはGauche自身で書いてありますから、その機能が無いとブートストラップできない)。現時点では、srfi-1, srfi-13, srfi-19, util.match, gauche.collection, gauche.sequence他数個のモジュールがプリコンパイルされたバイナリとしてロードされるようになっています。
もう少し実験を続けて、ワークフローとかツールのインタフェースとかが固まったら正式にサポートします。 |
|
shiro #-|2006/11/29(水) 14:09 [ 編集 ]
|
> (*バイト* コードじゃなくて,gauche では) ワードコード ?
あ,なるほど.すいません,そこらへんは曖昧に使っていて,私的には 「抽象 (中間) マシンコード」 ぐらいの意味合いで使ってました.まぎらわしくてすいません.
>> そもそもGaucheのコンパイラはGauche自身で書いてありますから、その機能が無いとブートストラップできない
機能があることは知っていた (黎明日記さんとこなど) のですが (私は cvs head などは追いかけてはいないので… それどころかまだ 0.8.7 がメインです) 最新版ではいつのまにかサポートされていた (あるいはアンドキュメントなだけで,最初から) のかと思ったのです (^-^;
将来的にはサポートされる,という情報だけでも,大変ありがたいです.期待して待ってます :-)
# gauche のブートストラップ compiler は,compile.scm を C に (genstub のようなツールを使って) トランスレートしたものを使っているのではないか ? とか,今まではなんとなく思っていたのですが,実際はもっと複雑そうですね.
# っと,今思い出して検索したら,ズバリ解説されてましたね (汗) なるほど,なるほど.参考になります.
http://d.hatena.ne.jp/scinfaxi/20061028
>> shiro 『compile.cはCのソースではありますが、中身は「コンパイル結果のVMのコードをCの静的データ配列としてダンプしたもの」なので、普通に言う Cへのトランスレータとはちょっと意味が違いますね。イメージとしてはJavaの.classファイルに近いですが、独自フォーマットを作るかわりにCの処理系を利用して普通のオブジェクトファイルにしているってことです。 で、GaucheにはSchemeソースをそういう形のCファイルへと変換する機能があって、compile.cもその機能を使うことでGauche自身がcompile.scmから生成してます。』 |
|
あろは #wNX6xxGw|2006/11/29(水) 14:38 [ 編集 ]
|
Gaucheではキーワードとシンボルはdisjointで、:okはそのままだとキーワードとしてパーズされちゃいます。どうしても:okという「シンボル」が欲しければ |:ok| って感じでエスケープして下さい。
でもGaucheベースでゆくならキーワードでもいいと思うけど… |
|
shiro #-|2006/11/29(水) 15:30 [ 編集 ]
|
>> |:ok|
おぉお,なるほど.そんな技が… 大変参考になりました.
# reader macro をもっとちゃんと勉強しないとなぁ.余談ですが,|:ok| が,なんか人の顔みたい.
確かに keyword でも良いかもしれませんね.ただ,今回の場合は,排他的にキーワード引数に取る必要があるので,エラーチェックが若干面倒になりそうな気もしますが…
# :ok と :ok-cancel とかが同時に指定されるとマズイ
あと,gauche では,キーワードは keyword という特殊なオブジェクトなんですね.知りませんでした (^-^;
# 今ちょっとキャッシュしか残ってませんが,GHG では,R5RS との互換性などが議論されてるみたいですね. |
|
あろは #wNX6xxGw|2006/11/29(水) 20:04 [ 編集 ]
|
> 確かに keyword でも良いかもしれませんね. xyzzyでもキーワードですしね。
> xyzzy lisp には仕様書とか無いからな.何を返しておけば良いのか良くわからん. 個人的な印象ですが、戻り値が参照され無そうな場合はtを返していることが多い気がします。 |
|
NANRI #LYu7.Z8o|2006/11/29(水) 22:38 [ 編集 ]
|
あれ ? そうだったのですか ? なるほど.
# あんまり Common Lisp を知らない人
ただ,そもそも,純 Scheme には keyword って概念は無いですからね (^-^;
>> 戻り値が参照され無そうな場合はtを返していることが多い気が
なるほど.私は,なんか nil が返される場面が多いな,と思っていたのですが.
今のところは,とりあえず戻り値は,xyzzy は t/nil を返す感じですが,gauche なので #t/#f を返す感じになってますねぇ. |
|
あろは #wNX6xxGw|2006/11/30(木) 00:06 [ 編集 ]
| |
|
コメントの投稿
|
|
|
トラックバック
|
トラックバックURLはこちら
http://alohakun.blog7.fc2.com/tb.php/560-7efb9269
| |
| |