以前のエントリ CSV ファイルを読むコード で、ちょろっと
いかにも Scheme なコードなのでループと状態マシンに書き直すとかの高速化の余地がありますね。
などと書いていたが、先日本当にそんな事態に遭遇してしまった。 今迄ちっこいファイルしか読んでなかったので、ちょっとメモリ使用量が多いなー。 まぁ、Gauche と違って immutable な文字列じゃないんで共有とかできないから効率わるいんじゃろ。 などと目を背けていたのですが、ある程度の規模の CSV を読んだら途端に性能問題が。うがぁ。
posted at: 00:54 | path: /lisp | permanent link to this entry | Tags: lisp
私はもう長いこと MUA として Mew を使っているのですが、最近 CVS カレントに cmew.rb, smew.rb なるファイルが増えていました。のぞいてみると SQLite の DB に メールのパスと Message-Id を覚えておいて、指定したメールのスレッドを表示するようです。
手元に環境がなかったので C でごまかしてみました。ライセンスは MIT ライセンスで。 いろいろ機能がなかったりメールの解析が手抜きだったりしますが、物好きな方はどーぞ。 パッチ等は大歓迎です。:-)
# メールのインデックスを作成します % cmew ~/Mail/id.db ~/Mail # 指定したメッセージ ID のファイルを表示します % smew ~/Mail/id.db メッセージID メールディレクトリ /home/onjo/Mail/lisp/10.mew /home/onjo/Mail/lisp/11.mew /home/onjo/Mail/lisp/15.mew /home/onjo/Mail/lisp/16.mew
Mew から使うにはどこかパスの通ったところにインストールして、cmew を実行し、mew-prog-smew 変数を smew.rb から smew に変更しましょう。 運がよければ動くでしょう。
ToDo は以下の通り:
- メールの解析がいい加減
- メールディレクトリの扱いがいい加減
- リストやハッシュがいい加減 (cons とか make-hash-table がないと駄目な人になってしまっていた…)
このへん からどーぞ。
posted at: 23:36 | path: /emacs | permanent link to this entry | Tags: emacs
CL の人が「なんでも再帰」しない理由は、再帰うんぬん以前にループの構文があるからでしょう。 「"Hello" を10 回出力してね繰り返してね」といわれたら〜はいはい繰り返しね、って感じで。
;; すっきり CL (loop rpeeat 10 do (print "hello")) (dotimes (i 10) (print "hello")) ;; 偏見に満ちた Scheme (llet loop ((n 0)) (when (< n 10) (print "hello") (loop (+ n 1)))) (foreach (lambda () (print "hello")) (iota 10))
だいたいのコンパイラだと最適化オプションで ON/OFF できますしね。 毎回完璧に最適化されちゃうとデバッグがなぁ〜
とうわけで、 http://www.cliki.net/Tail%20Recursion の翻訳(CL の人が末尾再帰について一般的に思う事)。
posted at: 23:43 | path: /misc | permanent link to this entry | Tags: lisp
会社の同僚から Matz 日記 (http://www.rubyist.net/~matz/20070827.html) のエントリを紹介された。
(Common) Lispの最大の問題は「コマンドが作れないこと」という分析。ライブラリは簡単に作れるんだけど。
ここでコマンドとはコマンドラインから実行できるもの、あるいはexecシステムコールで呼び出せるもの(Windowsならstartか)。
いや、もちろん作れるんだけど、イメージをまるごと含む形になるため、ほんの小さなプログラムでも巨大になりがち。 これでは「伝統的な開発モデル」にはうまくはまらない、ということ。
Smalltalkでも似たような状態なんだけど、とはいえ、これはLisp(や Smalltalk)の最大の利点でもあるわけだし。利点と欠点が表裏一体ということか。
Matz さんのような影響力の大きい人にこーゆうことをかかえると、コミュニティの小さい Common Lisp 界隈はほんというに死活問題なんですが。
まず、CLISP ならフットプリント 4MB 程度で #!/usr/bin/clisp なスクリプトがかけます。 スクリプトによるコマンドでいいなら別に特別巨大というわけでもないと思います。(手元の Ruby のバイナリが 3MB でした)
スタンドアロンバイナリ化にしても、 CLISP ならイメーズファイル + スクリプトのバイトコードサイズになりますので、Ruby や Python の py2exe, Perl の PAR などのツールと比較しても特別巨大というわけではないと思います。
まぁ、SBCL とかの話なんでしょうけど、この手の話題で一番巨大なバイナリを生成する処理系を対象にするのはどうかと。 C の場合は libc (ランタイム) と gcc (コンパイラ) が分離してるけど Lisp だと一体化してるのが普通ですからね。
コンパイラに gcc を使う ECL なら小さなスタンドアロンバイナリも出せます (libecl.so は 3MB 程度あるけど)。
ネイティブコードコンパイラを備えた処理系でも、たとえば LispWorks なんかはコンパイラの機能を外したりして スタンドアロンバイナリのサイズを抑える(でも 8MB とかあるけど)機能があったりしますし。
スクリプト的な用途だと Emacs Lisp や Gauche もオススメです。
posted at: 22:23 | path: /misc | permanent link to this entry | Tags: lisp
Lisp と関係ない事は書くまいと思っていたのだが、ついつい……。
これまで絶好調だった Windows Vista だが、今日いきなり「非正規品の可能性があります」とかいわれた。 最初は暗号化ファイルシステムサポートのために、わざわざ Ultimate にアップデートしたのに…あの量販店め、偽物つかませやがったか? 何度やっても WGA 認証はエラー。 3 回しか使えない貴重なインシデント使ってしまったり、あちこちサポートフォーラムを見てまわったり。
そうしていたら、それっぽい問題を発見。 Validation issues - Microsoft is having WGA server problems. (http://forums.microsoft.com/Genuine/ShowPost.aspx?PostID=2053834&SiteID=25) WGA サーバーのトラブルらしい。どうもこの状態で再起動すると Aero 等、機能が制限されてしまうようだ。 BitLocker や暗号化ファイルシステム機能とかも制限されたら洒落にならないので、再起動できない。 ためす勇気もありません。うむむ、あと三日かぁ。
フォーラムでもみんな怒ってますね。Vista はかなり安定しているだけに、こんなところに落し穴があったとは。 同様の症状の方は再起動に気をつけましょう……。はやく復旧してくれぇぇぇ。
追記: 翌日には無事認証が通りました。よかった。
posted at: 23:51 | path: /misc | permanent link to this entry | Tags: windows
忙しくて遅くなってしまいましたが、 Franz から Allegro Common Lisp 8.1 がリリースされています。 というか、先月末だったんですが忙しくて紹介できずに伸び伸びになってました。
8.1 からは Allegro Cache, Allegro Btree に加えて Allegro Graph が Professional Edition、Express Edition でも 制限つきで利用可能になりました。
忙がしくて気がついたらコレを逃がしてしまっていたという。
http://sdf-jp.org/bbs/viewtopic.php?t=5
来る6月16日は、SDFの20周年の誕生日です。 イベントが下記の通り行われます 20周年記念チャット・パーティー CDT 6pm~ (日本時間9amより) チャット参加者には抽選でビル・ガスパー氏のパズルが当たります。 SDF20周年についての詳細はこちらをご覧下さい(英語) http://sdf.lonestar.org/news/
SDF ということは、これ、あのレビーのハッカーズに出てきた Gosper 氏本人ですよねぇ。 するときっとパズルというのは http://www.gosper.org/ のトップのすごくカッコイイこれですよね。 「Bill Gosper's 12 Piece Twubblesome Twelve」うあぁぁぁぁぁ欲しかったぁぁぁ。
- 12 ピースのレーザーカットされた円盤のパズル
- すべてのディスクを大きな円の中につめ込むのが目的 (簡単だって?ハッ!!)
- 説明書と微細繊維の布つき
なんという一品。…ん、gosper.org から買えるな? $140 + 送料か。 普段は日記的なことは書かないようにしようと心がけているのですが、一応 Lisp がらみなので。
posted at: 22:26 | path: /misc | permanent link to this entry | Tags: lisp
id:rubikitch さんのところに C のライブラリを FFI 経由で呼びたい、というネタがありましたので解答しておきます。
[追記] 別ページ: http://lispuser.net/commonlisp/japanese.html へ移動。
static VALUE cg_s_guess(VALUE klass, VALUE str) {
const char*ptr;
int ret;
Check_Type(str, T_STRING);
ret = CharGuessInit();
ptr = GuessChardet((const char *)RSTRING(str)->ptr);
ret = CharGuessDone();
return ptr ? rb_str_new2(ptr) : Qnil;
}
上記のようなモジュールを、素直に CFFI で表現すると次のようになります。
posted at: 23:53 | path: /lisp | permanent link to this entry | Tags: lisp
Common Lisp における文字列は「Character」の列だ。C 言語などでは、文字列は実際にはバイト列と等価なので、 この辺は考え方を換える必要がある。もちろん、内部的には何かのエンコーディングによるバイト列を保持 しているわかけだが、I/O や、バイト列との変換には external-format を指定して内部エンコーディングから 目的のエンコーディングへと変換する必要がある。
[追記] 別ページ: http://lispuser.net/commonlisp/japanese.html へ移動。
文字列 (Character の列) <---- external-format ----> バイト列 (unsigned-byte の列)
この external-format は、バイト列への変換以外にも文字列のやりとりなど I/O ストリームでも使用する。 サポートされている external-format の種類や、その API については、処理系毎に異なるので各処理系のマニュアルを参照すること。
[AllegroCL] バイト列 => 文字列: ext:octets-to-string 文字列 => バイト列: ext:string-to-octets [LispWorks] バイト列 => 文字列: ext:decode-external-string 文字列 => バイト列: ext:encode-lisp-string [CLISP] バイト列 => 文字列: ext:convert-string-from-bytes 文字列 => バイト列: ext:convert-string-to-bytes [SBCL] バイト列 => 文字列: sb-ext:octets-to-string 文字列 => バイト列: sb-ext:string-to-octets
しかし、日本語を扱う上では文字列とバイト列の変換 API だけでは不十分な場合がある。 バイト列が手元にあったとして、これも文字列に変換したいケースを考えよう。 あなたの悩みはこうだ。「はて、このバイト列が文字列なのはわかっているが…エンコーディングは何だったっけ?」
文字列と external-format の例を示しつつ、バイト列のエンコーディングを推測する処理を作ってみる。
posted at: 22:49 | path: /lisp | permanent link to this entry | Tags: lisp
どう書く?のお題というと、こないだのメールのエンコードもなかなか厳しかったです。ライブラリが充実してないので。 で、 w-o-f TAB で with-open-file に補完、みたいな様子を見てもらうと 解く過程の Flash ムービー を撮ったのですが、 1分15枚の設定でやったら大失敗…。マウスの動きだけ妙に補完されて遅いし、タイプは荒い…。がっかり。
で、またまた Common Lisp には厳しいお題がでていました。
リフレクション系のお題の続編です。ローカル変数の内容を取得して連想配列(ハッシュ、辞書など)に詰めるコードを書いてください。 Pythonで表現すると、下のコードの???部分を埋めることになります。
>>> def foo(): x = 1 y = "hello" ??? return result>>> foo() {'y': 'hello', 'x': 1}
これに挑戦してみます。
しかし、コンパイラからするといわゆるローカル変数は定数である事がわかったり、未使用だったりすると最適化の対象にしやすいため 少なくとも変数名と値の対応を全て覚えているというのは期待できませんが…。
posted at: 23:44 | path: /misc | permanent link to this entry | Tags: lisp, doukaku
どう書く? というサイトで見かけた「n人中m人が当選するくじ (http://ja.doukaku.org/4/)」という問題が出題されていました。
;; 最初に投稿しようと思った例
(defun lot-A (lst m)
(assert (>= (length lst) m) () "...")
(flet ((random-select () (let ((e (nth (random (length lst)) lst))) (setf lst (remove e lst)) e)))
(loop repeat m collect (random-select))))
;; 実際に書くであろう例
(defun lot-B (lst m)
(assert (>= (length lst) m) () "...")
(srfi-1:take (alexander:shuffle lst) m))
結局 Lisp で書くと (loop repeat m collect (random-select)) あるいは (take (shuffle lst) m) と書くだろうなーと。 標準機能だけで一関数にはしないだろうなぁ、とか悩んでしまった。フォルダ内のバックアップ削除のお題にしても CL-FAD ライブラを使って (fad:walk-directory dir #'byebye-backup) と書くだろうしなぁ。むむむ。
また、掲示板では次のような書き込みを見かけたので勝手に添削。
From: [163] デフォルトの名無しさん <> Date: 2007/07/01(日) 21:04:30
http://karetta.jp/article/blog/ll-spirit/033840 これをCLで素朴にやってみたんですけど誰か添削してくれませんか。
油売り算というものらしい。
斗桶 (a) に油が 1 斗 (10 升) ある。これを等分したい。7 升枡 (b) と 3 升枡 (c) しかない。この 2 つの枡 だけで、5 升ずつ等分する方法を記述せよ。
この問題を解くにあたり、(a) に入っている油の容量を第 1 引数、(b) の容量を第 2 引数、(c) の容量を第 3 引数とするプログラムとせよ。
posted at: 00:19 | path: /lisp | permanent link to this entry | Tags: lisp
はてなで Lisper を発見。
というわけで、私もチャレンジ。
ここで作った Common Lisp 用 text.csv モジュール 置いておきます (Gauche の text.csv の移植)。 ドキュメント書いたら CLiki にでも載せようかな。
posted at: 01:12 | path: /lisp | permanent link to this entry | Tags: lisp
404 Blog Not Found:Code Snippets - reduce(l|r)を実装汁! ネタ。 Common Lisp には標準であったので話にならなかった。10 分を切れてよかった。
(defun reducel (fn lst) (reduce fn lst)) (defun reducer (fn lst) (reduce fn lst :from-end t))
つまらないので Prolog 版。うむ、やっぱり Prolog はいい。call で高階関数も使えるし(funcall が許せない人には不評かもしれないが)。
% reducel/3
reducel(Fn, [Head | Tail], Result) :- reducel(Fn, Head, Tail, Result).
% reducel/4
reducel(_, Result, [], Result).
reducel(Fn, Init, [Head | Tail], Result) :-
call(Fn, Init, Head, Temp),
reducel(Fn, Temp, Tail, Result).
% reducer/3
reducer(Fn, List, Result) :-
reverse(List, [Init | Temp]),
reverse(Temp, Tail),
reducer(Fn, Init, Tail, Result).
% reducer/4
reducer(_, Result, [], Result).
reducer(Fn, Init, [Head | Tail], Result) :-
reducer(Fn, Init, Tail, Temp),
call(Fn, Head, Temp, Result).
ついでに Allegro Prolog 版。直訳。
;; reducel/3
(<-- (reducel ?fn (?x . ?xs) ?result) (reducel ?fn ?x ?xs ?result))
;; reducel/4
(<-- (reducel ? ?result () ?result))
(<- (reducel ?fn ?init (?x . ?xs) ?result)
(is ?temp (funcall ?fn ?init ?x))
(reducel ?fn ?temp ?xs ?result))
;; reducer/3
(<-- (reducer ?fn ?lst ?result)
(is (?x ?xs) (list (first (last ?lst))
(butlast ?lst)))
(reducer ?fn ?x ?xs ?result))
;; reducer/4
(<-- (reducer ? ?result () ?result))
(<- (reducer ?fn ?init (?x . ?xs) ?result)
(reducer ?fn ?init ?xs ?temp)
(is ?result (funcall ?fn ?x ?temp)))
最後に組み込みの reduce を使わずに CL で書いた例。 Scheme の人が再帰版は書くでしょうからあえて反復で。
posted at: 23:08 | path: /misc | permanent link to this entry | Tags: misc, prolog
前に FizzBuzz ネタやったときに、なぜか懐しい事を思い出したので。
ふと Lisp の応用例(?)といえそうなネタを思い出した。Microsoft の Age of Empire II というゲームを御存知だろうか? 私が学生時代にとても流行したゲームなんですが、これって AI をプログラミングする機能がありましてね。 AI Scripters (http://www.aiscripters.com/index.php) というサイトで解説されてます。 誰もこれを Lisp とは呼びませんでしたが、皆でハックして AI War とかやって遊べたんですね。
(defrule
(current-age == dark-age)
(building-type-count mill < 2)
(sheep-and-forage-too-far)
(or
(players-unit-type-count my-player-number 122 > 0)
(players-unit-type-count my-player-number 216 > 0)
)
(can-build mill)
=>
(chat-local-to-self "Found some hunting, building a mill.")
(build mill)
(disable-self)
)
前置記法じゃないけど S 式ですね。しかも宣言的。LISA の推論ルールみたいな形式。 ルールを定義して、マッチするとアクションが動作する。ゲームの状態 (Fact) をベースに ルールとアクションを定義する。いやーいいですね。
(defrule 条件 => アクション)
;; 例: エリート侍ユニットの人数に応じて不気味な笑い (defconstant villager-goal 1) (defrule (unit-type-count elite-samurai == 5) => (set-goals samurai-goal 5)) (defrule (unit-type-count elite-samurai == 10) => (set-goals samurai-goal 10)) (defrule (samurai-goal == 5) => (chat-to-all "fufufu ...")) (defrule (samurai-goal == 10) => (chat-to-all "hehehehe ..."))
今から思えば Norvig の教科書にでてくる宣言的スタイルです。 私の中では結構理想的なわかりやすさでしたね。S 式ベースの DSL の好例というか。 破城槌 + ナイトの数が揃ったら敵の城を破壊に!! とかルールを書いてくわけです。
S 式だから読み難いんだ、S 式は皆に嫌われている、というのはプログラマだけなんじゃないですかねー。 あんまりこの AI スクリプトの仕様に文句つけたりする人はいなかったように思います。 言語仕様等の詳細は AI Scripters のページをどうぞ。あるいは製品の CD にドキュメントが入っていたと思います。 [1] 用語は Lisp とかなり異なっていますが、ほぼ困る事はないでしょう。 というかエンジンが Lisp ということはないだろうから、これは「Lisp 以外で S 式を利用した例」なんだろうなー。 S 式はだめだめだという主張を良く聞きますが、いや、そんなことはない!! 実は某超人気ゲームでも採用されていた!! かつ、ユーザーコミュニティにも受け入れられていた!! なんつって反論できますね。さすがにちょっと古すぎか :-)
| [1] | 製品 CD-ROM の DOCS フォルダ以下の CPSB.DOC (Computer Player Strategy Builder Guide) ですね。今見直してもいいですね〜。やっぱ製品はしっかりしてるなー。 |
で、本題ですが Prolog は楽しい。なんというか、昔教わっていたときに
factorial(0,1).
factorial(N,X) :-
factorial(N1, X1),
N is N1 + 1,
X is N * X1.
という定義を打ちこんで、動作を試していたら…
?- factorial(3, X). X = 6 Yes ?- factorial(6, X). X = 720 Yes ?- factorial(X, 6). X = 3
当時は最後のでびっくりした。え、なんで?みたいな。 Prolog の挙動は独特なんですが、当時は あんまりわかってなかったですからね。手元の junk ディレクトリから時代を追っていくといろいろあっておもしろい。
posted at: 23:48 | path: /misc | permanent link to this entry | Tags: misc, prolog
http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm
FizzBuzz 問題というのが流行していたらしい。プログラマなら一瞬でかけるはずー、と。 Lisp なら二分以内に…。
(defun fizzbuzz ()
(loop for i from 1 to 100
do (format t "~A~%"
(cond ((= (mod i 15) 0) "FizzBuzz")
((= (mod i 3) 0) "Fizz")
((= (mod i 5) 0) "Buzz")
(t i)))))
format の t を忘れて結構ギリギリだった…。
choice(N, X) :- N mod 15 =:= 0, X = 'FizzBuzz', !.
choice(N, X) :- N mod 3 =:= 0, X = 'Fizz', !.
choice(N, X) :- N mod 5 =:= 0, X = 'Buzz', !.
choice(N, N).
fizzbuzz(a) :-
between(1, 100, N),
choice(N, X),
write(X), nl,
fail.
うーん。カットが見えないほうが好きなんだよなぁ。
fizzbuzz() :-
between(1, 100, N),
( N mod 15 =:= 0 -> X = 'FizzBuzz';
N mod 3 =:= 0 -> X = 'Fizz';
N mod 5 =:= 0 -> X = 'Buzz';
X = N ),
write(X), nl,
fail.
こうかなー。再帰させたらこうか。
fizzbuzz(N) :-
N =< 100,
( N mod 15 =:= 0 -> X = 'FizzBuzz';
N mod 3 =:= 0 -> X = 'Fizz';
N mod 5 =:= 0 -> X = 'Buzz';
X = N ),
write(X), nl,
M is N + 1,
fizzbuzz(M).
で、なんで Prolog かというと、要するに Allegro Prolog のサンプルを示したかったからです。
posted at: 22:36 | path: /misc | permanent link to this entry | Tags: misc, prolog
On Lisp 読んでる人からこのツッコミ (lhttp://lispuser.net/memo/lisp/2007-03-31-23-26.html) の意味がよくわかんないという反響や、 ちょっと非 Lisper の人との議論にでてきたので、ついでに CLHS 3.1.1 Introduction to Environments の翻訳をしてみました。 環境とスコープとエクステントをおさえればいいかなー (と、おもったんですが環境だけで力つきた)
posted at: 23:31 | path: /lisp | permanent link to this entry | Tags: lisp
著名な Lisper である Joe Marshall 氏の Wiki で見かけた記事の翻訳です。 (http://code.google.com/p/jrm-code-project/wiki/ProgrammingArt)
posted at: 22:16 | path: /lisp | permanent link to this entry | Tags: lisp
あろはさんところ (http://alohakun.blog7.fc2.com/blog-entry-701.html) の GCC の最適化関連の話らしいネタ で Shiro さんのコメントに compiler-macro がさらっと出てきいたので。
CommonLisp処理系の多くは、formatの文字列が定数ならコンパイル時に「format文字列をコンパイル」 します。つまりformat文字列を解釈して行われるであろう動作を直接コードとして吐き出します。 前にコメントしたcompiler-macroを使ってるんで、デフォルトの最適化に不満があれば 自分で最適化するコードを書いてオーバライドできます。
Allegro CLに書いた正規表現ライブラリでも、正規表現が定数文字列の時はコンパイル時に 「その正規表現に従って実行するプログラム」を生成してコンパイルするようなcompiler-macro を書きました。
まあ、アドホックな職人技の世界ではありますね。
ここで compiler-macro とはなんぞや?と思った人や、ふつうのマクロを思いうかべた人のために 軽く説明しておきます。
C の printf と同様に Lisp でも FORMAT は遅いので、パラメータが全部定数ならコンパイル時に 解決してくれてもいいじゃんと思うことはありませんか? そこで ANSI CL のコンパイラマクロです。FORMAT はあんまり高速じゃないので、コンパイル時に引数が 定数のみなら超絶最適化をかましてしみます。
posted at: 14:57 | path: /misc | permanent link to this entry | Tags: misc, lisp, perl
flatline さんとこの On Lisp ネタに反応。
http://d.hatena.ne.jp/flappphys/20070324#p1
サークルの先輩から「なんかどのLispも動的スコープだと思っている人が多くない?」と指摘を受ける.
ELispは最初から動的スコープ.
Schemeは静的スコープで有名である.動的スコープの実現はライブラリによる方針を取っている.SRFIに(割と歴史の古い)fluid-letが提案されたものの取り消され,現在 "parameter" 系が標準になっているらしい.マルチスレッドとの相性が肝のようだ.
- http://practical-scheme.net/gauche/man/gauche-refj_26.html Gauche ユーザリファレンス: 4.6 変数束縛
- http://srfi.schemers.org/srfi-15/ SRFI 15: Syntax for dynamic scoping.
- http://srfi.schemers.org/srfi-39/ SRFI 39: Parameter objects
Common Lispも基本は静的スコープだが,動的スコープも仕様に組み込まれている.defparameter等のオペレータで定義した変数は動的スコープになる(special variable, dynamic variable)し,ローカル変数はdynamic-extentとしてdeclareすれば動的スコープに変更できる.
- http://www.lisp.org/HyperSpec/Body/mac_defparametercm_defvar.html Macro DEFPARAMETER, DEFVAR
- http://www.lisp.org/HyperSpec/Body/dec_dynamic-extent.html Declaration DYNAMIC-EXTENT
しかし「トップレベルで静的スコープの変数を作るにはどうするの?」これが分からない.できないんじゃね?
どこかで見たような話題ですね。みんな引っかかっているような気が。 On Lisp の継続のところでこれでハマった記憶がありますねー。 たしかに defvar は変数を special 宣言しちゃう [1] のでスペシャル変数しかできないです。 ANSI Common Lisp でトップレベルのレキシカルスコープ変数を実現するにはコレ。
;; lexical (defvar *actual-cont* #'values) (define-symbol-macro =cont= *actual-cont*)
シンボルマクロは special じゃないので、これで擬似的にトップレベルの静的スコープが実現できます(もちろん変数名のキャプチャには注意しましょう。どうしても嫌なら gensym を使ってもいいかも)。あと、 * で囲んだ変数名はスペシャル変数につけるものと相場が決まっているので、ここでは cont の変数名を変更しています。
元ネタを探したら c.l.l のスレッド が見つかりました。Google は便利だなぁ…。
とかいってるうちに Shiro さんから回答がでてましたね。 でもまぁ、こっちの方法も今流行の SBCL でも警告がでないという利点があるので載せておきます。
| [1] | defvar は大抵 special 宣言 + setq みたいな実装になっています
;; GNU CLISP より抜粋
(defmacro defvar (&whole whole-form
symbol &optional (initial-value nil svar) docstring)
(unless (symbolp symbol)
(error-of-type 'source-program-error
:form whole-form
:detail symbol
(TEXT "~S: non-symbol ~S cannot be a variable")
'defvar symbol))
(if (constantp symbol)
(error-of-type 'source-program-error
:form whole-form
:detail symbol
(TEXT "~S: the constant ~S must not be redefined to be a variable")
'defvar symbol))
`(LET ()
(PROCLAIM '(SPECIAL ,symbol)) ;; (proclaim (special ...))
,@(if svar
`((UNLESS (BOUNDP ',symbol)
(SYS::SET-SYMBOL-VALUE ',symbol ,initial-value))))
,@(if docstring
`((SYS::%SET-DOCUMENTATION ',symbol 'VARIABLE ',docstring)))
',symbol))
;; SBCL より抜粋
(defmacro-mundanely defparameter (var val &optional (doc nil docp))
#!+sb-doc
"Define a parameter that is not normally changed by the program,
but that may be changed without causing an error. Declare the
variable special and sets its value to VAL, overwriting any
previous value. The third argument is an optional documentation
string for the parameter."
`(progn
(eval-when (:compile-toplevel)
(%compiler-defvar ',var)) ;; (proclaim (special ...))
(eval-when (:load-toplevel :execute)
(%defparameter ',var ,val ,doc ',docp (sb!c:source-location)))))
(defun %compiler-defvar (var)
(sb!xc:proclaim `(special ,var)))
|
posted at: 23:26 | path: /lisp | permanent link to this entry | Tags: lisp
ぐあー出先からだとメールも更新もできないーと思っていたんですが、 テキストで ReStrurecturedText 形式のファイルを置くだけなんで、 FTP が使えれば ここの更新はできる事に気がつきました。
で、はてなダイアリー界隈に Lisper を多数発見?
posted at: 22:48 | path: /misc | permanent link to this entry | Tags: misc, lisp, perl
On Lisp が発売されたとの事で、Lisp 界隈では喜びの声が多数あがっていますね。 なんか表紙もカッコよさそうです。うひょう。これで、Lisp に興味持つ人が増えるといいなぁ〜と、妄想しつつ。
日本の Lisp 界ですが、 Web でみる限り学校でやるのは Scheme がほとんどたと思うので Scheme 人気のほうが高いのはなんとなくわかるんですが、 日本では、別の入門ルートとして xyzzy で Lisp に触れる -> Lisp そのものに興味をもつ -> Lisp 大好き というのもありそうですよねー(私はこのルートです)。
で、ふと、Common Lisp のページ http://ja.wikipedia.org/wiki/Common_Lisp を参照したところ… ガガーン。Scheme のページより圧倒的に活気がないッ。こいつぁーまずい。 これでは Lisp に興味 -> Wikipedia -> Scheme へ転向という流れが目に浮ぶようだッ。
というわけで、大至急ある程度充実している Wikipeida 英語版を翻訳してみました。 原文は Lisp-2 vs Lisp-1、Scheme との違いなども抑えていて結構まとまっているかんじだし。
投稿前に見直しもかねてここに貼っておきます。ツッコミ歓迎です。
posted at: 00:58 | path: /lisp | permanent link to this entry | Tags: lisp
この記事は書きかけです
今回は前回作った LISP インタプリタにマクロを実装します。 構文木 Eval 式だと最適化の余地とかあんまりなくて面白くないんで、 次回は大きくリファクタリングしてバイトコード VM の導入ですかねぇ。
各章の先頭の煽り文句は、昔某掲示板に投稿した銀河帝国ネタからの抜粋です。↓こんなの。 もちろん第二ファウンデーションは Scheme 使いの集団の予定でした。第一とは仲が悪いあたりも似てますね。
第一銀河帝国は、何世紀にもわたって少しずつ頽廃と崩壊を続けていた。 だが、その事実を理解している人間は、帝国の生んだ最後の天才科学者、ハリ・セルダンだけだった! 彼は自ら完成させたλ歴史学を用いて帝国の滅亡とその後に続く3万年の暗黒時代を予言したのだ。 この暗黒時代をただの千年に短縮するため、セルダンは二つのファウンデーションを設立した…
...
ガールはセルダンに尋ねた。
「でも、なぜ強制的にマイナーにならなければならなかったのですか?」間を置いて、「私には教えていただけないのですか?」
「まだ、だめだ。今のところは次の事を知っているだけで十分だ。実用的な Common Lisp がターミナスに建設されるということ。 そして、もうひとつが銀河系の反対側の端に。つまり、”星界の果て”に建設されるということ。」
...
ついにセルダンは計算をやめて、いった。「これは10年後の LispOS だ。これをどう解釈するかね?」
かれは小首を傾げて、待った。
ガールは信じられないようにいった。
「完全な滅亡です!GUI を装備していたということすら忘れられている!しかし…しかし、そんなことはありえません。 いまだかつて… MAC LISP コンパイラは Fortran コンパイラにさえ負けなかったというのに…」
「これこれ、この結果がどうやって出たか見ただろうに。しばらく記号体系は忘れて、言葉で表現してみたまえ」
「Lisp マシンそのものが増大する汎用マイクロプロセッサのパワーに押されて性能的に厳しい状態に置かれます。 また、CPU パワーやメモリを有効活用するために C のような言語が普及し、それにつれて、 Lisp の GC 等は性能上の問題とみなされるようになります。 その結果、S 式に対する反感が増大し、メモリ管理は原始的な手動管理に退行し、 バッファオーバーフローが社会的問題になります」
posted at: 22:54 | path: /lisp | permanent link to this entry | Tags: lisp
息抜きに小ネタをば。Shiro さんとこの Lisp:S式の理由 の中のネタより。
個人的には、condは (Paul GrahamがArcで提案しているように) 括弧をひとつ 省いて、(cond 述語 式 述語 式 ...) でいいんじゃないかという気がします。 式に複数の処理を書きたければbeginを使うと。
(cond (predicate x) (begin (do-something) (do-something2)) (predicate y) (do-another-thing) else (do-whatever))また、letについては、束縛とボディの式に別種の括弧を使うとか:
(let [x (calculate-x a b c)] [y (calculate-y d e f)] body ...)
なるほど、この辺は Lisper 間での意思統一が難しそうですね。 括弧の量が問題になるのなら、種類ではなく括弧を。 区切りがよくわからないなら記号を導入すべきではないでしょうか。
;; 個人的に好みの cond
(cond (predicate x) => (do-something1)
(do-something2)
(predicate y) => (do-another-thing)
else => (do-whatever))
矢印派の勢力を拡大すべく 矢印cond のムービーを用意しました。 総製作時間 5 分に渡る大長編。
あ、しまった => だと SRFI の拡張 cond/case と紛らわしいですね…… orz じゃあ let の拡張は <- を使って…。
;; 個人的に好みの let
(let
x <- (calculate-x a b c)
y <- (calculate-y d e f)
in
body ...)
寝る前に矢印 let にもチャレンジ。 矢印let ムービーも用意しました。見直すと、不要な処理がありますね。
つうか in は不要なんじゃないかとか。いや、でもエディタ支援のときに キーワードが欲しいなー。でもキーワードという概念が Lisp に合わないような。
こうして構文を作るのは簡単ですが「正しい事」へと到達するのは難しかったのです。 そして Lisper は満足できずに結局 S 式を使いつづけるのでした。 おしまいおしまい。
みんなが好き勝手にいろいろ試すのを「マクロの暗黒面」としてとらえる人も 多いかと思いますが、「正しい事」は多くのハッカーが議論を尽した結果得ら れるものなんです。…と正当化してみましたがやっぱ苦しいですかね。
でも使ってみると Emacs の支援が弱くなるので、構文だけつくっても今一なんだよなぁ…。 ねむいのでこのへんで。
posted at: 01:54 | path: /lisp | permanent link to this entry | Tags: lisp
各方面で大絶賛の嵐。というより Lisp を叩くのが人気。
こうして不人気の再生産に入るのか?
追記:1/28 Shiro さんのところに素晴しいエントリが。
S式のメリットをLisperに尋ねれば、エディタがどうの、マクロがどうの、といった 回答が真っ先に返って来ると思うんですが、そういう理屈をいくら理解しても S式がダメな人がS式を好きになったりはしません。どうも、もっと根本的な 感覚に大きな隔たりがあるような気がします。非Lisperから理解しがたい、 Lisperの持つ感覚とはどんなものなんでしょうか。Lisp脳から見た世界はどん なものなのでしょうか。
ちょっと前に S 式の利点(エディタがどうの)を説明しようと必死になっていましたがその通りですね。 しかも、このエントリは(マクロがどうの)といった話をしてしまいました :-(
posted at: 20:50 | path: /lisp | permanent link to this entry | Tags: lisp
Lisp の括弧は良くネタにされます。実際、大量の過去は最初のインパクトは強烈だったのを覚えています。 いったいなぜ Lisper は括弧を捨てないのでしょう? 歴史的にみれば括弧を好まない Lisper も居ます。古くは CMU の AI リポジトリに CGOL という ALGOL ライクな 構文の Lisp リーダ/ライタがあり、これは S 式と相互に変換できました。CGOL で書いて、S 式で表示とかができたわけですね。
;;Execute by typing "cl < demo.txt". (load "parser.cl") (load "cgol.cl") #.(cgol) scripting $ % C-style comments % % first some easy ones % 1+1 $ 2*3/6 $ % assignment % a:= 7 $ b:= a*7 $ % try out operator precedence % 2*3/6 $ 100+3*5 $ 100*3+5 $ % should be 47 % 2+2+6*7+7/7 $ % floats use same arithmentic operators % 2+95.3/7.25 $ % can return value of arbitrary element in sequence % 2+2 ; 3+3 ; 4+4 $ 2+2 & 3+3 ; 4+4 $ 2+2 ; 3+3 & 4+4 $ eval $ % turn off evaluation to avoid undef'ed variables % % if's compose nicely % if (a<b) then if (a<c) then a else if (b<c) then b else c $ % try some Lisp operators % [12,4,3,5,6] $ a^b @c$ \a,b,c; p;q;r $ % escape into Lisp directly % !(make-array '(100 2) :element-type 'integer) $ eval $ 4 isin [12,4,3,5,6] $
ほかにも Dylan などは S 式を捨てて ALGOL ライクな構文を導入することで普及を目指しました。 現在でも Lisp に S 式以外の構文を持たせようとする試みは Lisp を学ぶ者が誰でも一度は挑戦する定番の課題となりました [1] 。 comp.lang.lisp には毎年一度は確実にその手を話題が投稿されます。 「C/Python/Ruby ライクな構文シュガーを考えたんだ!!」 「C++ みたいにドットでメソッド呼び出しを書けるマクロをつくったよ!!」 などです [1] 。
自分の経験だけでも、「メソッド呼び出しを C++ 風に(C/C++ から入ってきたので)」「インデントで構造を表す(Python の影響)」「後置記法に (forth の影響)」「区切記号の活用 ((f3 (f2 (f1))) -> f1 | f2 | f3)」などやりましたが、どれも精々ユーザーインターフェースの一貫としてちょっと使ったくらいで、自分でプログラミングするための S 式を完全に置きかえるには至りませんでした [2] 。
| [1] | (1, 2) リーダーマクロなどがある所為か、Common Lisp の界隈では特にその傾向が強いように思います。まぁ、 Scheme も SRFI でインデントベースの表記法を規定しているので結局皆考える事は一緒なのでしょうが… |
| [2] | S 式の表示を視覚的に工夫する試みも、学生の研究から Emacs での 「S 式を強調する 5 つの方法 : Five Approaches to S-Expression Highlighting 」までいろいろあります。 |
CGOL から数十年が立ち、多くの試みがなされましたが、 Lisp 使いは結局今も S 式をつかっています。なぜでしょうか? 曰く「優れた Lisp 使いには括弧が気にならなくなる」「インデントで構造は読むので」などなど諸説あります。 中には「Lisp 脳になると括弧が気持ち良くなる」といった胡散臭いもまである始末。 個人的な感想からいうと、Lisper は S 式の利点 を理解して 便利だから 使っているのであって、 もしこれよりも編集しやすく読みやすく、表現力に富む記法が開発されれば喜んで S 式を捨てるでしょう。
Lisp を勉強するほぼすべての人は、S 式の代替となる表現を考えようと試みます。 そして、ある程度の経験を積めばそれは実現できます。 しかし、それは S 式の利点 を 100% 引き継げない場合がほとんどなのです。
しかし、自分の体験に照し合わせてみると、この S 式の利点 は文章を読んだだけえは実感できませんでした。 自分の経験を思い出してみれば、最初は師匠の操作を後からのぞいてその編集操作のカーソルの奇妙な動きを観察してたものです。 現在は昔に比べれば圧倒的に Web で簡単に Lisp の情報は手に入りますが、この「S 式の便利さ」の編集部分を目にする機会は 依然として少ないように思います。 というわけで、マクロやプログラム==データなどいろいろ小難しく聞こえる S 式のメリットは よく見かけますが、「編集が楽」に関しては「Emacs を使えば楽」という程度の説明で あっさり終ってしまう場合が多いように思います。そこで、今回は括弧の編集における利点を解説してみようと思います。
posted at: 20:36 | path: /emacs | permanent link to this entry | Tags: emacs
この記事は書きかけです
Lisp 普及を目指しているのに、まず入門記事がないのはどうよ?とか言われて、 グサっときたので。他の言語の入門記事より Lisp の特徴を前面に出していこ うということで、「Lisp を作りながら Lisp を学ぶ」を目指します。 いま入手できる Lisp 処理系ってほんとうに良くできているものが多いのですが、 自分でつくってみると、「本物」のすごさが良くわかるようになるでしょう。
ネタ元: Java で 500 行の Lisp にインスパイアされました。
http://itpro.nikkeibp.co.jp/article/COLUMN/20060922/248738/ (http://d.hatena.ne.jp/textfile/20061204/lisp 経由)
ちょっと探してみると http://tociyuki.cool.ne.jp/archive/index.html とか http://www.biostat.wisc.edu/~annis/creations/PyLisp/ とかありますが、 Lisp をやるなら Lisp がいちばん!!
100 行程度で超シンプルな Lisp インタプリタを作成してみます。 オリジナルの Java 版と同様にマクロはないですが、短かくてもちゃんとクロージャは備えています。 (Lisper な人には断わっておきますが、 Lisp-1 です)
posted at: 03:54 | path: /lisp | permanent link to this entry | Tags: lisp
めでたく SBCL 1.0 がリリースされました!! …が、他のニュースサイトに 遅れること一週間。個人的目玉は
ですが、今さら新機能を羅列しても独自色がでないので 1.0 以降の情報をば。 SBCL CVS 版では↓のような結構大きな変更がはいってます。
CLISP CVS 版では、gtk モジュールが導入されてます。Glade でデザインし た xml を読み込んで使えるようになるらしく、CLISP での GUI 環境の改善 に役立つかもしれません。今後の動向が注目されます。
SLIME は 12 月初旬頃の CVS から swank::*coding-system* の書式が キーワードから文字列にかわりました。古い .slime.lisp を使っていると エラーになるので注意してください。
;; (setq swank::*coding-system* :utf-8-unix) ; old style (setq swank::*coding-system* "utf-8-unix") ; new style
また SBCL 1.0.0.18 から入ったクロスリファレンス (xref) がサポートされる ようになっています。
posted at: 04:54 | path: /lisp | permanent link to this entry | Tags: lisp
ちょっと古いネタですが comp.lang.lisp での Zach Beane の投稿。途中まで 訳して、「後で訳す」になっていたのだがlemonador.com に取り上げられてい たので続きをやってみました。
posted at: 23:32 | path: /lisp | permanent link to this entry | Tags: lisp
ネタがないので http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Scheme%3a%e6%95%b0%e9%81%8a%e3%81%b3 よりパズルに挑戦。
S E N D + M O R E --------- M O N E Y (S, M != 0 かつ S, E, N, D, M, O, R, Y はユニークな 0..9 の整数)
まず欲しい関数を考える。↓のような感じでズバっと解答がほしい。
CL-USER> (solve "SEND" "MORE" "MONEY") SEND + MORE = MONEY ???? + ???? = ????? CL-USER>
全組み合わせを考えるとー 10 個の数値から 8 個を取り出すんだから (* 10 9 8 7 6 5 4 3) で 1814400 程度かな?この程度であれば、探索時間はあまり 問題にならないような気もするけれど、メモリはどうかなー。全リストを返す と、たとえば S, E, N, D, M, O, R, Y を fixnum のリストで表現したとして コンスセルで 8 セル。CAR, CDR がそれぞれ 4 バイトとして、文字に対応する 数値のリストが 8 x 8 = 64 バイト。全部 collect すると、
64 バイト * 1814400 通り = 116,121,600 バイト = 100MB
これは、現在メモを書いている Lisp 環境 (CLISP on coLinux メモリ 256MB 割り当て) では厳しそうなので、パターンをリストにあつめてから map する 方向ではなく、パターンを生成したらそれを引数に関数を呼び出すようにしよう。
;; こんなつもり (combinations fn 0..9 8) => (funcall fn '(8 7 6 5 4 3 2 1 0)) => (funcall fn '(9 7 6 5 4 3 2 1 0)) => (funcall fn '(7 8 6 5 4 3 2 1 0)) ... => (funcall fn '(1 2 3 4 5 6 7 8 9))
で、このリストの数字と文字との対応をとって SEND + MORE = MONEY を満すか どうかを検査する、と。
posted at: 00:11 | path: /lisp | permanent link to this entry | Tags: lisp
いつのまにやら SBCL 0.9.17 と CLISP 2.40, 2.41 がリリースされてます。
SBCL は weak hash の実装 と Windows用インストーラの試験版 、FFI の External-format サポート、CLISP は SLIME で関数の引数名が表示されるようになった のと libsvm サポート が主要な変更点です。
今迄 CLISP ではコンパイルされた関数は引数の名前を保持しておらず、arg0 arg1 ... のような表示になっていたのですが、今回から最適化オプション space の値を設定することによりパラメータ名を保持するようになりました。 2.40 以前を使っている人は、さっそく 2.41 に更新しましょう。
CLISP 2.41 ごった煮版 も用意しました。詳細は CLISP のページ で。
posted at: 23:38 | path: /lisp | permanent link to this entry | Tags: lisp
私が最初に見かけた Catalyst のサンプルが taskpad.jp みたいなのを Catalyst で作ってみる でした.Catalyst の感じがつかめて非常に参考になりました.
そこで,最近入手した AllegroCL で似たような事をやってみようと思います. まぁ,偉そうな事いいながらマニュアル片手に調べながらちまちま書いてるわ けですが.
posted at: 22:25 | path: /lisp | permanent link to this entry | Tags: lisp
Emacs 仲間が dired モードの場合に拡張子で色をつけたい,とボヤいていまし た.で,調べたついでにここのネタにします.たしかに font-lock 周りの説明 は不足気味な上,dired の色付けに関するドキュメントはさらに少ないように 思います.
dired モードは Emacs の標準色付け機構 font-lock を使ってディレクトリや マークなどの操作に対応したハイライトをしています.dired がやっているの は実際には font-lock 用の正規表現とフェイスを設定しているだけで実際に色 をつけているのは font-lock 機構です.おおまかに説明すると
[dired-mode 起動時] 1. dired 起動 2. dired-mode 関数が呼ばれる 3. バッファローカルの変数 font-lock-defaults に dired-font-lock-keywords を指定
したがって,dired-font-lock-keywords を通じてカスタマイズが可能です.で は,dired.el の dired-font-lock-keywords 定義を見てみましょう……と思っ たんですが,はい,長いですね.カスタマイズ用の関数を用意しました.
(defvar *original-dired-font-lock-keywords* dired-font-lock-keywords)
(defun dired-highlight-by-extensions (highlight-list)
"highlight-list accept list of (regexp [regexp] ... face)."
(let ((lst nil))
(dolist (highlight highlight-list)
(push `(,(concat "\\.\\(" (regexp-opt (butlast highlight)) "\\)$")
(".+" (dired-move-to-filename)
nil (0 ,(car (last highlight)))))
lst))
(setq dired-font-lock-keywords
(append *original-dired-font-lock-keywords* lst))))
使い方は次の通りです.
(dired-highlight-by-extensions
'(("txt" font-lock-variable-name-face)
("odql" "tmpl" font-lock-type-face)
("lisp" "el" "pl" font-lock-constant-face)))
色づけを変更したい場合は再度 dired-highlight-by-extensions を呼び出して ください.
このように (拡張子 [拡張子] ... フェイス) という形式のリストでファ イル名を拡張子に応じて色付けします.ただ,ファイル数が遅いと性能にモロ に効いてきますので使いすぎには御注意下さい.:-)
posted at: 23:06 | path: /emacs | permanent link to this entry | Tags: emacs
泥くさい例もあったほうが宣伝になるかと思い ~/bin の中から公開しても差し 使えないような 小物 Lisp プログラム を公開.
(defpackage :mkindex (:use :cl :indexer))
(in-package :mkindex)
(define-root (merge-pathnames "doc" (user-homedir-pathname)))
(define-category "Lisp Resources"
:link '(("Common Lisp Hyper Spec" "./HyperSpec/Front/index.htm")
("Common Lisp The Language 2nd Edition" "./cltl/cltl2.html")
("Practical Common Lisp" "./web/www.gigamonkeys.com/book/index.html")
("Paul Graham" "./web/www.paulgraham.com/index.html")
("Dream Songs" "./web/www.dreamsongs.com/index.html")
("Pascal Contanza" "./web/p-cos.net/index.html")
("Structure and Interpretation of Computer Programms"
"./web/www-mitpress.mit.edu/sicp/index.html")
("SICM" "web/swiss.csail.mit.edu/~gjs/6946/sicm-html/index.html")
))
(define-category "Other Documents"
:link '(("PostgreSQL 8.1 (ja)" "./postgres/index.html")
("Statistics with R" "./web/zoonek2.free.fr/UNIX/48_R/all.html")
("Perl and Shift_JIS" "http://homepage1.nifty.com/nomenclator/perl/index.htm")
("Perl Hints" "http://www.geocities.co.jp/SiliconValley-Oakland/4080/")
("Perl and Unicode" "http://www.lr.pi.titech.ac.jp/~abekawa/perl/index.html")
))
(define-category "Maxima Documents"
:pred (filter :directory "lisp" :filetype "pdf"))
(define-category "PDF Documents"
:pred (filter :directory "ebook" :filetype "pdf"))
(define-category "CHM Documents"
:pred (filter :directory "ebook" :filetype "chm"))
(generate-index)
posted at: 03:10 | path: /lisp | permanent link to this entry | Tags: lisp
Lisp マシンのマニュアルが HyperText 形式で公開されています!!
http://bknr.net/static/lmman/frontpage.html
現在の dynamic-extent による最適化と同等の機能が組み込まれています.ヒー プ上ではなくスタック上にリストを確保する事により GC の手間を省く機能の ようです.
http://bknr.net/static/lmman/fd-con.xml#stack-list-section
コルーチンやジェネレーターなどが当時からメジャーな手法だった事がわかり ます.この機能は Common Lisp にないですねぇ.
http://bknr.net/static/lmman/fd-sg.xml#Resuming%20of%20Stack%20Groups-section
当時の LOOP マクロ!!
http://bknr.net/static/lmman/looptm.xml
CLOS に影響を与えたオブジェクトシステム FLAVORS !! 聞いたことはありま したが,こーゆう感じだったんですねー.
http://bknr.net/static/lmman/flavor.xml
(send オブジェクト メッセージ) という形式ですが,すでに多重継承や総 称関数など現代に通じる機能が見られますね.(Allegro Common Lisp には後 方互換のために flavors がまだ附属しています)
Lisp マシンのネットワーク機能 Chaosnet です.当時は今のように標準化され た規格がなく,ごちゃまぜの複数規格が混沌としていたため,この名前が付い たとか聞いたことがあります.
http://bknr.net/static/lmman/chaos.xml
その他便利なユーティリティ関数.documentation, ed, dribble などは Common Lisp 規格にありますね.その他の metering や who-call などは処理 系の拡張ライブラリの定番ですね.
http://bknr.net/static/lmman/fd-hac.xml
ほかにもコンパイラの章には現代のコンパイラマクロの前身のような機能や開 発環境との連携を前提とした機能など Lisp Machine ならではの機能が記述さ れています.並列処理用機能 Processes などは現代の各種処理系の MultiProcessing パッケージに似ています.How To Read Assembly Language なんて章があるあたりハッカー精神を感じますね.
posted at: 19:30 | path: /lisp | permanent link to this entry | Tags: lisp
Bugzilla や影舞など BTS もいろいろありますが,うちでは実績と伝統のある RT をつかってます.http://www.bestpractical.com/ より最新の rt-3.6.0.tar.gz などはだいぶ見た目も現代的になってきて良いかんじです. (この見た目の変更は 3.5 以降のものですので,3.4 以前使っている人にしか わかりませんが…)
が,たとえば更新に失敗すると,一瞬にして「ほらみろ.なんでも IT とか言 うから (中略) やっぱ Excel による台帳管理だな!!」という具合に底辺環境 までレベルダウンしてしまいそうなので更新はしくじれません.そんなわけで, まず個人の環境から更新してみます.
posted at: 21:59 | path: /misc | permanent link to this entry | Tags: misc, perl
リリースノート翻訳 ( 原文 ),ついでに Takashi Hiromatsu さんの NTEmacs のバイナリ と組み合わせて簡単に CLISP + SLIME + LTK による GUI までを体験できるパッケージ を用意しました.詳しくは CLISP のページ を御覧ください. 手軽にフルセットの Lisp 開発環境が体験できます!! Happy Hacking!!
今回は何気に Win32 上での I/O の高速化 が大きいと思います.
posted at: 21:42 | path: /lisp | permanent link to this entry | Tags: lisp
ふと思い出したので, comp.lang.lisp の new to lisp というスレッドで 紹介されていたネタを.
最初は Lisp 初心者の質問に答えるという通常の流れなのですが,最初は定番の ネタ (SICP の紹介とか) なんですが,途中からおもしろくなってきます.
やー,それらは良いプログラムかもしれないね.でも私は Lisp を初める初心 者にとって本当に良いアドバイスなのかいまだに確信がもてません.私が書い て,実行できた最初のプログラムは次のようなものでした:
10 PRINT "HELLO" 20 GOTO 10それは次のようになるでしょう:
(TAGBODY 10 (PRINT 'HELLO) (GO 10)):-)
という記事から BASIC ライクな手続きの話に.そこで,Joe Marshall 氏の衝 撃の発言が.
posted at: 10:20 | path: /lisp | permanent link to this entry | Tags: lisp, comp.lang.lisp
Lisp に興味のある方ならば,MOP : Meta Object Protocol を聞いた事がある と思います.最近は CLISP でも実装されており,ほぼ全ての Common Lisp 処 理系で利用可能になっています.一ユーザーとしてどのようなメリットがある かを考えてみます.
cs-user> (defclss node () ((title :initarg :title) (data :initarg :data))) ; Evaluation aborted cs-user> (defclass node () ((title :initarg :title) (data :initarg :data))) #<standard-class node> cs-user> (defvar a) a cs-user> (defvar b) b cs-user> (setq b (make-instance 'node :title "Data 1 - COPY" :data '(1 2 3))) #<node #x20EA5A56> cs-user> a #<node #x20E9053E> cs-user> b #<node #x20EA5A56> cs-user>
さて,A の中身を表示したいと思いませんか?あるいは,データのコピーを簡 単に作りたいという要望もあるでしょう.真っ先に考えつくのは以下のような ものです.
(defmethod show ((obj node))
(with-slots (title data)
node
(format t "TITLE: ~A~&DATA: ~A~&" title data)))
(defmethod shallow-copy ((obj node))
(make-instance 'node
:title (if (slot-boundp obj 'title) (slot-value obj 'title) nil)
:data (if (slot-boundp obj 'data) (slot-value obj 'data) nil)))
しかし,これは node クラスの定義が変更されるたびにメンテナンスが必要に なります.スロットが追加されたら?名前がわったら?そう,メソッドも変更 が必要になるのです.この問題を Meta Object Protocol を使って解決してみ たいと思います.
posted at: 22:40 | path: /lisp | permanent link to this entry | Tags: lisp
howm の記事やメールなどが増えてきて探すのが面倒になってきたので全文検索 の導入を考えはじめました.まず Hyper Estraier がよさそうなので,評価も とりあえずなんとか検索できるような Emacs Lisp ででっちあげました.
1. HyperEstraier をインストールする (estcmd にパスが通っている事)
2. hyperestraier-config を設定する
+ :linux プラットフォーム
+ :howm 種別
+ :index インデックスのディレクトリへのパス
+ :create インデックス作成時のコマンド
+ :update インデックス更新時のコマンド
この設定の部分でインチキ臭ささが酷いですね.なんと NTEmacs でも動かした い,かつ,ファイルの指定は find ... |grep のように指定したかったと いう個人的要望で,なんと .bat というバッチファイルを生成してシェルから 実行するという手抜きっぷりです.
posted at: 05:49 | path: /emacs | permanent link to this entry | Tags: emacs
データを保存したくて CFFI 使って GDBM とのインターフェースを書いていた んですが,オブジェクトを保存したいケースにでくわして,CL-Store 使うか… とおもったところで,CL-Prevalence の事を思いだしました.インストールし ただけで使ってなかったんですが,使ってみたら非常に便利でした.
CL-PREVALENCE とは Sven Van Caekenberghe 氏による ObjectPrevalence の Common Lisp 実装です. CL-PREVALENCE は S-XML を使用した XML シリアライズプロトコルを用いています.また,よ り Lisp ライクな S 式ベースのシリアライズプロトコルも存在します.
Object Prevalence 2001 年に Klaus Wuestefeld によって提案された,シンプ ルでかつ興味深いコンセプトを持った技術です.IBM developerWorks にわかり やすい 入門記事 があります.Java による主な実装は Prevayler と呼 ばれており,Wiki サイト(雑然としています)に多くの情報と活発な議論があ ります.Object Prevalence の主要な特徴のほとんどは学術論文 A Simple and Efficient Implementation for Small Databases (Birrell, Jones, and Wobber [1987]) で説明されています. 基本的なアイデアは以下のようなものです.
これで Object Prevalence のコンセプトはすべてです.利点と制限事項の詳細は以下の通りです.
CL-PREVALENCE のコードは Sven Van Caekenberghe によって書かれました.
(defparameter *prevalence-directory* (merge-pathnames #p"./Local Settings/Temp/" (user-homedir-pathname)))
(defclass <Entry> ()
((id :initarg :id)
(name :initarg :name)
(link :initarg :link)))
(defun test-1 ()
(let* ((system (cl-prevalence:make-prevalence-system *prevalence-directory*)))
(setf (cl-prevalence:get-root-object system :entries) (make-hash-table :test #'equal))
(let ((entries (cl-prevalence:get-root-object system :entries)))
(dotimes (i 100)
(setf (gethash i entries) (make-instance '<Entry>
:id i
:name (format nil "16進数:0x~X" i)
:link (gethash (- i 1) entries)))))
(cl-prevalence:snapshot system)))
(defun test-2 ()
(let* ((system (cl-prevalence:make-prevalence-system *prevalence-directory*))
(entries (cl-prevalence:get-root-object system :entries))
(keys (loop for k being the hash-keys of entries collect k)))
(dolist (k (sort keys #'<))
(let ((v (gethash k entries)))
(with-slots (id name link)
v
(format t "~&key: ~A => object: ~A (id:~A, name: ~A, link: ~A)~%" k v id name link))))))
test-1 関数でルートオブジェクトとしてハッシュを容易し,そのハッシュに 登録しておくだけで DBM ライクな使い方ができるようになります.しかも,文 字列以外のオブジェクトを簡単に登録できます.
LispWorks 4.4.6 for Windows での Object Prevalence のサンプルを作成してみます.
posted at: 03:02 | path: /lisp | permanent link to this entry | Tags: lisp, translation
つらつらと comp.lang.lisp への投稿を眺めていたところ,面白い記事を発見 しました.Writing machine code from LISP スレッドへの Frank Buss 氏の投 稿 http://groups.google.com/group/comp.lang.lisp/msg/6d9cbc0fd337431b です.なんと CFFI を使って配列を用意し,そこに機械語のコードを埋め込ん で関数として呼び出してしまうという荒技です.
元の投稿はリストの合計値を求めているだけだったので,32 ビットでフィボナッ チ数を求める処理にチャレンジしてみました.
;; フィボナッチ数計算
(defun fib (n)
(loop with a = 0
with b = 1
repeat n
do (psetf a b
b (+ a b))
finally (return a)))
これを機械語に変換します.いきなり機械語はキツいので,一旦アセンブラで 考えます.
;; フィボナッチ数計算 (アセンブラ) [必須レジスタの保存] ;; パラメータ n を受けとる movl 4(%ebp), %edx ;; a = 0 xor %eax, %eax ;; b = 1 xor %ebx, %ebx inc %ebx ;; repeat n LOOP: test %edx, %edx jz END dec %edx ;; ループ内の処理 ;; ecx レジスタに a+b の値を計算 mov ecx, eax add ecx, ebx ;; a <- b mov eax, ebx ;; b <- a+b mov ebx, ecx ;; ループの処理 jmp LOOP END: [必須レジスタの復元]
あとはこのコードに等しいベクタを作り,それを一引数の関数として呼び出します.
posted at: 05:00 | path: /lisp | permanent link to this entry | Tags: lisp