2009/03/31

SERIES の encapsulated

Common Lisp の SERIES with-open-file 等の unwind-protect を使う場合はencapsulated を使うといいらしい?

encapsulated の第二引数で使えるのは SCAN-FN, SCAN-FN-INCLUSIVE, COLLECT-FNのいずれか。

よくわかってない。。。詳細は SERIES に添付の s-doc.txt を参照。

(require :series)
(use-package :series)

(defun scan-file-wrap (file name body)
`(with-open-file (,file ,name :direction :input) ,body))

(defmacro simple-scan-file (name)
(let ((file (gensym)))
`(encapsulated #'(lambda (body)
(scan-file-wrap ',file ',name body))
(scan-fn t
(lambda ()
(read ,file nil))
(lambda (x)
(read ,file nil))
#'null))))

(let ((x (simple-scan-file "/tmp/b.txt")))
(collect-sum (map-fn t (lambda (x) (* x x)) x)))

2009/03/29

CL パッケージの最も長いシンボルを SERIES(series:collect-max)で

以前 CL パッケージで中で最も長いシンボルはどれか探すのを SERIES でやろうとした。そのとき series:collect-max の使い方をよく理解してなかった。第1引数に数値のシリーズをとるので、最大長は返せるけど、その最大長を持つシンボルは返せないと思っていた。

でも、第二引数に第一引数と対応するシンボルのシリーズを渡してやるとちゃっとシンボルの方を返してくれた。

この最大のものを返すといのは loop マクロが苦手としているところで、iterate なんかが上手に解決しているところ。SERIES でもきれいに書けてよかった。

(require :series)

(let* ((symbols (series:scan-symbols :cl))
(lengths (series:map-fn t (lambda (symbol)
(length (symbol-name symbol)))
symbols)))
(series:collect-max lengths symbols))

2009/03/22

Common Lisp で rgerp しようとした scratch

またそのうちちゃんとしよう。

(eval-when (:compile-toplevel :load-toplevel :execute)
(require :cl-fad)
(require :cl-ppcre))

(setf *ed-functions*
(list (lambda (x)
(asdf:run-shell-command "emacsclient -n ~a" x))))

(defun ensure-pathname (x)
(typecase x
(pathname x)
(string
(parse-namestring
(if (char= #\~ (char x 0))
(concatenate 'string (namestring (user-homedir-pathname))
(subseq x 2))
x)))))

(defclass grep-result ()
((pathname :initarg :pathname :accessor pathname-of)
(line-number :initarg :line-number :accessor line-number-of)
(line :initarg :line :accessor line-of)
(base-dif :initarg :base-dir :accessor base-dir-of)))

(defmethod relative-path ((x grep-result))
(concatenate 'string "./"
(enough-namestring (pathname-of x) (base-dir-of x))))

(defmethod print-object ((x grep-result) stream)
(format stream "~a:~a:~a"
(relative-path x) (line-number-of x) (line-of x)))


(defun grep-file (pattern file dir)
(with-open-file (in file)
(loop for line = (read-line in nil)
for i from 1
while line
if (cl-ppcre:scan pattern line)
collect (make-instance 'grep-result
:pathname file
:line-number i
:line line
:base-dir dir))))

(defun rgrep (&optional pattern dir filter)
(unless pattern
(write-string "pattern: " *query-io*)
(setf pattern (read-line *query-io*))
(write-string "dir: " *query-io*)
(setf dir (read-line *query-io*))
(write-string "filter: " *query-io*)
(setf filter (read-line *query-io*)))
(let (result
(dir (ensure-pathname dir)))
(apply #'cl-fad:walk-directory
dir
(lambda (file)
(handler-case (setf result
(nconc result (grep-file pattern file dir)))
(error (e)
(format *error-output* "~a" e))))
(when filter
(list :test (lambda (file)
(cl-ppcre:scan filter (namestring file))))))
(format t "-*- mode: grep; default-directory: \"~a\" -*-~&"
dir)
(loop for i in result
do (format t "~a~&" i))
result))

(rgrep "defmacro|defun"
"~/letter/lisp/try/"
"\\.lisp$")

;;(ed (ensure-pathname "~/.emacs"))

2009/03/21

[Common Lisp] cl-blogger

Plato Wu さんの後押しがあり Muse で書いて Blogger にポストするプログラムcl-blogger として Google Code にあげた。さらに Plato Wu さんはラベルを指定する機能も追加してくれた。ありがとうございます。

; labels: ラベル1, ラベル2 のように書くとラベルが指定できる。私自身もこの機能が欲しかった。

[Common Lisp] cl-win32ole で日時を扱えるようにした

cl-win32ole で日時を扱えるようにした。

Common Lisp になぜか使いやすい日時のデータ型がないので、それも作ってみた。

darcs get http://li31-15.members.linode.com/darcs/simple-date-time

以下、テスト用のコード。create-object の2番目の引数で GC 時に指定したメソッドを実行するようにした。下の例だと、(setf ex nil sheet nil) で参照のなくし、(gc :full t)するとquit が呼ばれる。

(require :cl-win32ole)
(use-package :cl-win32ole)

(progn
(defparameter ex (create-object "Excel.Application" :quit))
(setf (slot-value ex 'visible) t)
(defparameter sheet
(ole (slot-value ex 'workbooks)
:open "/Users/ancient/Documents/a.xls" :worksheets :item 1))
)

(print (ole sheet :range "A1:D1" :value))

(setf (ole sheet :range "A2:B2" :value) (list nil nil))
(setf (ole sheet :range "A2:B2" :value)
(list
(make-instance 'dt:date-time :year 1973 :month 4 :day 26
:hour 0 :minute 0 :second 0 :millisecond 0)
(make-instance 'dt:date-time :year 1973 :month 4 :day 26
:hour 23 :minute 24 :second 25 :millisecond 26)))

(setf ex nil sheet nil)
(gc :full t)

2009/03/20

[SLIME] sayoonara

SLIME を終了させるには SLIME の repl で

,sayoonara
と入力すればよかったのか。いまごろ気づいた。

もう M-x slime-quit-lisp はやめようw

2009/03/17

[FreeMind] Linux での FreeMind で日本語フォント名をデフォルトに指定する

Linux 環境で FreeMind のデフォルトフォントを VL Pゴシック に指定したいときは~/.freemind/user.properties に次のように書く。

defaultfont = VL P\u30B4\u30B7\u30C3\u30AF

[日記] 卒園式

娘の卒園式。おめでとう。ありがとう。

娘よ、よく今日まで生きのびてくれた。ありがとう。

2009/03/15

[日記] 今日はひさしぶりに家でゆっくりできた

なものだから娘が一日中べったりだった。ひさしぶりに一緒に散歩にも行ったし。

そんでタコのパエリアを作った。

2009/03/08

[Common Lisp] Slimy hackathon Climacs と SLIME

Slimy hackathon に(ほんのすこしだけど)参加ということで、Climacs と SLIME の路線でいってみる。Climacs で C-c C-c とかすると SLIME(swank?)の機能でコンパイルしてるっぽいので、まずは Climacs と SLIME の関係を調べてみる。

Climacs のソースコードを slime, swank で grep しても何もひっかからない。

よくよく探してみると、McCLIM のソースコードの方に swank の文字があるのを見つけた。このファイル mcclim/Drei/lisp-syntax-swank.lisp

Climacs は McCLIM の Drei というテキストエディットのライブラリ(?)を使っている。その Drei の方が SLIME の機能を使ってるようだ。asd ファイルも drei のあたりで swank を depends-on している。

lisp-syntax-swank.lisp をみてみる。ファイル自体小さい。swank の機能もあまり使っていない。補完、コンパイル、定義、引数リストくらいかな。ざっとぬきだすとこんなかんじ。

  • (swank::swank-require :swank-c-p-c)
  • (swank::swank-require :swank-arglists)))
  • (swank::compile-string-for-emacs
  • (swank::compilation-result-notes result)
  • (swank::compilation-result-successp result)
  • (swank::compilation-result-duration result)
  • (swank::compile-file-for-emacs filepath load-p)
  • (swank::find-definitions-for-emacs name)
  • (swank::extra-keywords/make-instance 'make-instance class)
  • (swank::keyword-arg.keyword arg)
  • (swank::keyword-arg.arg-name arg)
  • (swank::keyword-arg.default-arg arg)
  • (swank::arglist symbol))
  • (swank::completions string (package-name default-package))

さて、ここからどこに進もうか。

2009/03/07

ひどい文章

前のエントリの文章はかなりひどい気がするが、思考を直訳するとだいたいあんな感じじゃないかなとも思う。

まあ、説明するのが下手だなぁ、と実感することが多いこのごろ。

だいたい思考とその表現(言語、日本語)にへだたりがありすぎるのがいけないと思います。

[Java] Eclipse でコンパイルできるのに Sun JDK だとコンパイルできない件を再考

コンパイラに差があるのはおいといて。。。

そもそも Z を型パラメータに含めるのが間違っているのかもしれない。というとこで Foo2。だいたい getZ が怪しい気もする。まえの例では X と Y に関係があったけど、そうじゃなくて。さらに W がいて、X と W は Z 経由でつながっていて、戻り値が X で引数が W の場合で、X と W が Z でつながらない場合はコンパイルエラーにしたい。まぁ Foo3 みたいなの。てのが Eclipse 上でもできてなかったってことか。来週の仕事でちゃんと考えよう。

package gen;

public class Foo2 {

public static interface ID<T1, T2> {
public T1 getValue(T2 arg);
}

public static interface IA<B> {
}

public static class A1 implements IA<B1> {
}

public static class B1 {
}

public static class E1 implements ID<A1, B1> {
public A1 getValue(B1 arg) {
return new A1();
};
}

public static class A2 implements IA<B2> {
}

public static class B2 {
}

public static class E2 implements ID<A2, B2> {
public A2 getValue(B2 arg) {
return new A2();
};
}

@SuppressWarnings("unchecked")
private <Z> Z getZ(Object y) {
if (y instanceof B1) {
return (Z) new E1();
}
if (y instanceof B2) {
return (Z) new E2();
}
return null;
}

public <X extends IA<Y>, Y> X bar(Y y) {
ID<X, Y> z = this.<ID<X, Y>> getZ(y);
return z.getValue(y);
}

public static void main(String[] args) {
Foo2 foo = new Foo2();
A1 a1 = foo.bar(new B1());
System.out.println(a1);

A2 a2 = foo.bar(new B2());
System.out.println(a2);

// コンパイルエラーとなる。
// a1 = foo.bar(new B2());
}
}
package gen;

public class Foo3 {

public static interface ID<T1, T2, T3> {
public T1 getValue(T2 arg);

public T1 getValue3(T3 arg);
}

public static interface IA<B> {
}

public static class A1 implements IA<B1> {
}

public static class B1 {
}

public static class C1 {
}

public static class E1 implements ID<A1, B1, C1> {
public A1 getValue(B1 arg) {
return new A1();
};

public A1 getValue3(C1 arg) {
return new A1();
}
}

public static class A2 implements IA<B2> {
}

public static class B2 {
}

public static class C2 {
}

public static class E2 implements ID<A2, B2, C2> {
public A2 getValue(B2 arg) {
return new A2();
};

public A2 getValue3(C2 arg) {
return new A2();
}
}

@SuppressWarnings("unchecked")
private <Z> Z getZ(Object y) {
if (y instanceof B1 || y instanceof C1) {
return (Z) new E1();
}
if (y instanceof B2 || y instanceof C2) {
return (Z) new E2();
}
return null;
}

public <X extends IA<Y>, Y> X bar(Y y) {
ID<X, Y, Object> z = this.<ID<X, Y, Object>> getZ(y);
return z.getValue(y);
}

public <A, C, E extends ID<A, ?, C>> A baz(C c) {
E z = this.<E> getZ(c);
return z.getValue3(c);
}

public static void main(String[] args) {
Foo3 foo = new Foo3();
A1 a1 = foo.bar(new B1());
System.out.println(a1);

A2 a2 = foo.bar(new B2());
System.out.println(a2);

a1 = foo.baz(new C1());
System.out.println(a1);

a2 = foo.baz(new C2());
System.out.println(a1);

// これはちゃんとコンパイルエラーになる。
// a1 = foo.bar(new B2());

// これもコンパイルエラーにしたい。
a1 = foo.baz(new C2());
}
}

それはともかく体調悪いな。仕事で無理しすぎだな。

[Java] Eclipse でコンパイルできるのに Sun JDK だとコンパイルできない件

Java のジェネリックを使っていて、Eclipse ではコンパイルできるのに Sun の JDK ではコンパイルできない事象に遭遇した。

勝手な解釈としては、下のコードのメソッド bar において、Z 経由で Y から X への型推論が Sun JDK ではできないのだと思う。引数の型、戻り値を受ける変数の型はダイレクトなので解決してくれるが、この場合のように型パラメータ間の関係までは知らないよ、というとこなんだろうか。

仕方ないのでメソッド bar2 経由で明示的に型を指定してみたところ動くようになった。

package gen;

public class Foo {

public static interface ID<T1, T2> {
public T1 getValue(T2 arg);
}

public static interface IA<B> {
}

public static class A1 implements IA<B1> {
}

public static class B1 {
}

public static class E1 implements ID<A1, B1> {
public A1 getValue(B1 arg) {
return new A1();
};
}

public static class A2 implements IA<B2> {
}

public static class B2 {
}

public static class E2 implements ID<A2, B2> {
public A2 getValue(B2 arg) {
return new A2();
};
}

@SuppressWarnings("unchecked")
private <Z> Z getZ(Object y) {
if (y instanceof B1) {
return (Z) new E1();
}
if (y instanceof B2) {
return (Z) new E2();
}
return null;
}

public <X extends IA<Y>, Y, Z extends ID<X, Y>> X bar(Y y) {
Z z = this.<Z> getZ(y);
return z.getValue(y);
}

public <X extends IA<Y>, Y> X bar2(Y y) {
// ここで bar の Z を明示的に指定する。
return this.<X, Y, ID<X, Y>> bar(y);
}

public static void main(String[] args) {
Foo foo = new Foo();
// JDK ではコンパイルエラー。Z 経由で Y から X の型が推論できないらしい。
// 互換性のない型; 推定型引数 gen.Foo.A,java.lang.Object は
// 型変数 X,Z の境界に適合しません。
// A a = foo.bar(new B());

// bar2 経由でなら ok
A1 a1 = foo.bar2(new B1());
System.out.println(a1);

A2 a2 = foo.bar2(new B2());
System.out.println(a2);

// ちなみに次のように引数と戻り値のタイプ不整合は Eclipse でも JDK でもコンパイルエラーとなる。
// a1 = foo.bar2(new B2());
}
}

全部 Eclipse のコンパイラですませればいいのにさ。