Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
LispUser.net
[go: Go Back, main page]

LispUser.net - LispMemo

Fri, 14 Dec 2007

Common Lisp による日常作業 -- CSV ファイルを読む (read-line, read-line-into, simple-stream-read-line とか)

以前のエントリ CSV ファイルを読むコード で、ちょろっと

いかにも Scheme なコードなのでループと状態マシンに書き直すとかの高速化の余地がありますね。

などと書いていたが、先日本当にそんな事態に遭遇してしまった。 今迄ちっこいファイルしか読んでなかったので、ちょっとメモリ使用量が多いなー。 まぁ、Gauche と違って immutable な文字列じゃないんで共有とかできないから効率わるいんじゃろ。 などと目を背けていたのですが、ある程度の規模の CSV を読んだら途端に性能問題が。うがぁ。


(続きを読む)

posted at: 00:54 | path: /lisp | permanent link to this entry | Tags:

Tue, 11 Dec 2007

メールの検索:cmew, smew -- cmew.rb, smew.rb の C による実装 for Mew

私はもう長いこと 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:

Sun, 16 Sep 2007

末尾再帰とループ問題

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:

Wed, 05 Sep 2007

Common 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:

Sat, 25 Aug 2007

Vista で初トラブル -- Microsoft の WGA サーバーのトラブル

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:

Tue, 14 Aug 2007

祝: AllegroCL 8.1 リリース

忙しくて遅くなってしまいましたが、 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:

Wed, 08 Aug 2007

CFFI で簡単 FFI - libcharguess, NKF32.DLL

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:

Tue, 07 Aug 2007

Common 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:

Wed, 01 Aug 2007

ローカル変数の一覧を取得 @ どう書く?.org

どう書く?のお題というと、こないだのメールのエンコードもなかなか厳しかったです。ライブラリが充実してないので。 で、 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: ,

Mon, 02 Jul 2007

どう書くとか油売り算とか

どう書く? というサイトで見かけた「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 引数とするプログラムとせよ。

(http://karetta.jp/article/blog/ll-spirit/033840 より)


(続きを読む)

posted at: 00:19 | path: /lisp | permanent link to this entry | Tags:

Fri, 29 Jun 2007

PNM (PBM, PNM, PPM) 形式の画像とか CSV ファイルとか

はてなで Lisper を発見。

というわけで、私もチャレンジ。

ここで作った Common Lisp 用 text.csv モジュール 置いておきます (Gauche の text.csv の移植)。 ドキュメント書いたら CLiki にでも載せようかな。


(続きを読む)

posted at: 01:12 | path: /lisp | permanent link to this entry | Tags:

Tue, 29 May 2007

Common Lisp や Prolog で Reduce(l|r)

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: ,

Thu, 17 May 2007

S 式ベース DSL の思い出とか 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: ,

Sun, 13 May 2007

Prolog で FizzBuzz (おまけ: AllegroProlog)

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: ,

Thu, 19 Apr 2007

Common Lisp Hyper Spec -- CLHS 3.1.1 Introduction to Environments の翻訳

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:

Wed, 11 Apr 2007

プログラミング・アート

著名な 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:

Sun, 01 Apr 2007

自力で最適化コンパイル -- コンパイラマクロ

あろはさんところ (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: , ,

Sat, 31 Mar 2007

On Lisp でハマるところ -- トップレベルでレキシカルスコープな変数を定義する in Common Lisp

flatline さんとこの On Lisp ネタに反応。

http://d.hatena.ne.jp/flappphys/20070324#p1

サークルの先輩から「なんかどのLispも動的スコープだと思っている人が多くない?」と指摘を受ける.

ELispは最初から動的スコープ.

Schemeは静的スコープで有名である.動的スコープの実現はライブラリによる方針を取っている.SRFIに(割と歴史の古い)fluid-letが提案されたものの取り消され,現在 "parameter" 系が標準になっているらしい.マルチスレッドとの相性が肝のようだ.

Common Lispも基本は静的スコープだが,動的スコープも仕様に組み込まれている.defparameter等のオペレータで定義した変数は動的スコープになる(special variable, dynamic variable)し,ローカル変数はdynamic-extentとしてdeclareすれば動的スコープに変更できる.

しかし「トップレベルで静的スコープの変数を作るにはどうするの?」これが分からない.できないんじゃね?

どこかで見たような話題ですね。みんな引っかかっているような気が。 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:

Wed, 28 Mar 2007

はてなダイアリーの Lisper にツッコミ

ぐあー出先からだとメールも更新もできないーと思っていたんですが、 テキストで ReStrurecturedText 形式のファイルを置くだけなんで、 FTP が使えれば ここの更新はできる事に気がつきました。

で、はてなダイアリー界隈に Lisper を多数発見?


(続きを読む)

posted at: 22:48 | path: /misc | permanent link to this entry | Tags: , ,

Mon, 19 Mar 2007

Wikipedia の Common Lisp ページ向け原稿

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:

Sun, 25 Feb 2007

作って学ぶ Lisp (2) -- 超やさしい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:

Sun, 28 Jan 2007

S式の限界

息抜きに小ネタをば。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 式を使いつづけるのでした。 おしまいおしまい。

みんなが好き勝手にいろいろ試すのを「マクロの暗黒面」としてとらえる人も 多いかと思いますが、「正しい事」は多くのハッカーが議論を尽した結果得ら れるものなんです。…と正当化してみましたがやっぱ苦しいですかね。

  • 矢印cond : 5 分でできる新しい cond (Flash ムービー)
  • 矢印let : 10 分でできる新しい let (Flash ムービー)

でも使ってみると Emacs の支援が弱くなるので、構文だけつくっても今一なんだよなぁ…。 ねむいのでこのへんで。

posted at: 01:54 | path: /lisp | permanent link to this entry | Tags:

Thu, 25 Jan 2007

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:

Wed, 20 Dec 2006

括弧の理由 (1) -- Emacs による S 式編集支援

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:

Fri, 08 Dec 2006

作って学ぶ Lisp (1) -- 超やさしいLispインタプリタの作り方

この記事は書きかけです

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:

Thu, 07 Dec 2006

祝 SBCL 1.0 リリース、と最近の SBCL, CLISP, SLIME などの CVS 版の情報

めでたく SBCL 1.0 がリリースされました!! …が、他のニュースサイトに 遅れること一週間。個人的目玉は

  • NIIMI Satoshi さんによる FreeBSD/x86 スレッドサポート (!!) や浮動小数 点例外の改善、Shift-JIS external format サポート。SBCL ユーザー は NIIMI さんにみんなで感謝しましょう。

ですが、今さら新機能を羅列しても独自色がでないので 1.0 以降の情報をば。 SBCL CVS 版では↓のような結構大きな変更がはいってます。

  • ユーザーが拡張可能な SEQUENCE 型
  • クロスリファレンス機能 (SLIME から利用可能になってます)

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:

Thu, 09 Nov 2006

「なるほど!」と思った瞬間 in Lisp

ちょっと古いネタですが comp.lang.lisp での Zach Beane の投稿。途中まで 訳して、「後で訳す」になっていたのだがlemonador.com に取り上げられてい たので続きをやってみました。


(続きを読む)

posted at: 23:32 | path: /lisp | permanent link to this entry | Tags:

Sat, 04 Nov 2006

SEND + MORE = MONEY

ネタがないので 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:

Thu, 19 Oct 2006

SBCL 0.9.17 と CLISP 2.41 リリース

いつのまにやら 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:

Sun, 10 Sep 2006

taskpad.jp みたいなのを AllegroServe + Webactions + AllegroCache でつくってみる [パクリ]

私が最初に見かけた Catalyst のサンプルが taskpad.jp みたいなのを Catalyst で作ってみる でした.Catalyst の感じがつかめて非常に参考になりました.

そこで,最近入手した AllegroCL で似たような事をやってみようと思います. まぁ,偉そうな事いいながらマニュアル片手に調べながらちまちま書いてるわ けですが.


(続きを読む)

posted at: 22:25 | path: /lisp | permanent link to this entry | Tags:

Wed, 30 Aug 2006

Dired に拡張子ベースで色を付ける - dired + font-lock

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:

Sun, 20 Aug 2006

日常的な Lisp

泥くさい例もあったほうが宣伝になるかと思い ~/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:

Thu, 17 Aug 2006

Lisp Machine のマニュアル

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:

Fri, 04 Aug 2006

RT 3.6.0 - Request Trakcer を導入

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: ,

Sat, 22 Jul 2006

CLISP 2.39 リリース : CLISP + SLIME + LTK パッケージ公開

リリースノート翻訳 ( 原文 ),ついでに 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:

Sun, 25 Jun 2006

典型的な Greenblat のコード

ふと思い出したので, 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: ,

Sat, 03 Jun 2006

SHALLOW-COPY : Meta Object Protocol の利用例 : オブジェクトをコピーする

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:

Thu, 18 May 2006

Emacs と全文検索 -- Hyper Estraier を使う

howm の記事やメールなどが増えてきて探すのが面倒になってきたので全文検索 の導入を考えはじめました.まず Hyper Estraier がよさそうなので,評価も とりあえずなんとか検索できるような Emacs Lisp ででっちあげました.

設定

1. HyperEstraier をインストールする (estcmd にパスが通っている事)
2. hyperestraier-config を設定する
   + :linux プラットフォーム
      + :howm 種別
         + :index インデックスのディレクトリへのパス
         + :create インデックス作成時のコマンド
         + :update インデックス更新時のコマンド

この設定の部分でインチキ臭ささが酷いですね.なんと NTEmacs でも動かした い,かつ,ファイルの指定は find ... |grep のように指定したかったと いう個人的要望で,なんと .bat というバッチファイルを生成してシェルから 実行するという手抜きっぷりです.

使い方

M-x hyperestraier-make-index
種別を聞いてくるので、答えるとインデックスを作成する (:create で指定したコマンドラインを呼び出すだけ)
M-x hyperestraier-update-index
種別を聞いてくるので、答えるとインデックスを作成する (:search で指定したコマンドラインを呼び出すだけ)
M-x hyperestraier-search
種別、検索フレーズ、結果の表示方法を指定して検索する (:index で指定した場所のインデックスを検索する)

ToDo

  • 検索結果バッファ用のモードを用意する (考えてるのは↓のような簡易的なもの)
    • p: 前の検索結果へ
    • n: 次の検索結果へ
    • v: 検索結果のファイルを開く ... とか?
  • Mew との連係
    • タグによる分類とかつけたいので結局 C で HyperEstraier の API を利用する


(続きを読む)

posted at: 05:49 | path: /emacs | permanent link to this entry | Tags:

Wed, 26 Apr 2006

CL-Prevalence : Common Lisp で Object Prevalence

データを保存したくて CFFI 使って GDBM とのインターフェースを書いていた んですが,オブジェクトを保存したいケースにでくわして,CL-Store 使うか… とおもったところで,CL-Prevalence の事を思いだしました.インストールし ただけで使ってなかったんですが,使ってみたら非常に便利でした.

CL-PREVALENCE 概要 (翻訳)

CL-PREVALENCE とは Sven Van Caekenberghe 氏による ObjectPrevalence の Common Lisp 実装です. CL-PREVALENCES-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]) で説明されています. 基本的なアイデアは以下のようなものです.

  • ほとんどのデータベースは,数百メガバイト程度のサイズしかないか,それよりも小さい
  • ほとんどのコンピュータは数百メガバイトのデータを RAM 上で操作できる.(大きなサーバなら数ギガバイト程度のデータを扱える)
  • オブジェクトをデータベースにマッピングするのは退屈で時間の無駄であるばかりか,複雑になったりエラーがでたりしやすい
  • データベースを捨てて,ドメインモデルオブジェクトをデーターベースとして使用することにしましょう
  • オブジェクトをファイルシステムのような永続領域にシリアライズしたり,デシリアライズして永続領域からオブジェクトを取り出せるようにしましょう
  • もしドメインモデルオブジェクトの完全な集合を永続領域の保存したいなら,スナップショットを作りましょう
  • クエリーとしてプログラム言語のデータ構造操作機能を使います.RAM 内のデータに対しては非常に高速ですから.
  • データとトランザクションを実行する関数を結びつけたトランザクションオブジェクトを使ったオブジェクトモデルを理解してください
  • ACID 属性を確保するために,それぞれのトランザクションを実行した後に,シリアライズして永続化します.これを トランザクションログ と呼びます.
  • 意図したか意図していないかに関わらず,システムがシャットダウンした時には,最初に最新のスナップショットをロードし,それぞれのトランザクションログを再実行してリストアします
  • トランザクションは決定的で,かつ,リエントラントでなければなりません (そして,必要ならば時刻を記録しておく必要があります)
  • マルチスレッドシステムでは,トランザクションはグローバルにシリアライズされます

これで Object Prevalence のコンセプトはすべてです.利点と制限事項の詳細は以下の通りです.

  • 最近のコンピュータの実装は優れているため,一秒間に数千トランザクションを実施し,また同じ速度でそれをリカバリーできます
  • トランザクションはシステムをブロックするため,短時間で完了しなければなりません - 全てが RAM 上にある間は対した問題ではありません
  • 完全に一貫したシテム状態を必要とするクエリーは,システムをブロックしなければなりません - さほどクリティカルでないクエリーは並列に実行できます
  • 実用上,トランザクションを実行する時にはまずシステムの状態をチェックし,必要ならエラーを返す必要があります.全てが一貫している時にのみシステムに変更を加えるようにします.トランザクション中は単独のスレッドのみがアクティブにならなければなりません.クエリーは可能なかぎり高速にデータを取得できます.この実装ではトランザクションは実行が成功した後に記録されます.
  • この実装ではトランザクション中に予期しないエラーに遭遇した場合に,(システムをリストアする事による)ロールバックが選択できます.トランザクション中でエラーが発生した場合に false を返す( もしくは no-rollback-error や,それを継承する事により)ロールバックするかどうかの条件を指定する事ができます.
  • 長時間に渡るトランザクションは問題となります
  • マスタとなるトランザクションログをレプリカに送ることにより,簡単にレプリケーションやクエリーのロードバランシングが可能です.また,バックアップやフェイルオーバーも実現できます.しかし,この実装はレプリケーションをまだ含んでいません.

CL-PREVALENCE のコードは Sven Van Caekenberghe によって書かれました.

日本語コンテンツ

CL-PREVALENCE サンプルコード

(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: ,

Wed, 19 Apr 2006

CFFI 入門 (2)

つらつらと 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: