Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2010-12-31

2010年を振り返る

| 18:02 | 2010年を振り返る - わだばLisperになる を含むブックマーク はてなブックマーク - 2010年を振り返る - わだばLisperになる

今年もだらだらと、まとめエントリーを書いてみたいと思います。

1月

2009年の12月からLISP365を開始した影響で毎日のようにKMRCLを眺める記事が載っています。

今年一年KMRCLのお蔭でエントリーを量産できました…。

Shibuya.lispのコードバトンにも参加していました。

2月

ほぼKMRCLを読んでるだけの月のようです。

3月

Shibuya.lisp TT#5開催

この月もほぼKMRCLを読んでるだけのようです。

4月

さすがにKMRCLばかりではまずいと思ったのか、CiNiiなどのLISP関係の論文を読み漁り始めていたようです。

80年代後半の論文には、知らなかったCLの処理系が結構載っていたりして発見が多かったです。

5月

どうやら発掘熱が高まっていた月のようです。

6月

7月

8月にTAO/ELIS復活祭があるので、TAO/ELISの論文を中心に読んでいたようです。

8月

東京から電車で片道5時間。JAISTまでELISが実働する様を目にしてまいりました。

復活祭では、Tachyon CLや、ELISの開発の方々とお話させて頂く機会があり、これが縁で大野さんには、Shibuya.lisp TT#6でお話頂くこととなりました。

Tachyon CLや、TAO/ELISでもちらほら動きがあるとかないとか、今後が楽しみです。

いつもアイデアを頂いているSmiley Hackathonですが、#9の会場が素晴らしく、この流れで、Shibuya.lisp Hackathon #1が企画されることとなりました。

Planet Common Lisp 日本 超手抜き版は恐らく自分が一番愛用していますが、質/量ともに充実しつつある気がしています。まあ、勝手に自分が集めて眺めて、にやにやしてるんですが…。

9月

KMRCLを眺めるのも段々行き詰まってきた頃だったと思います。

10月

先1年に渡り、繰り返しの構文は、Seriesを使う、ということに決めたため、Seriesの話題が多くなっているようです。

11月

Shibuya.lisp TT#6も無事開催されました。

  • 2日間まるごとLISPセミナー 2010 1/2日目参加

この月は、Seriesについてが多いです。

ちなみに、LAMBDAを使うなスタイル(2)が書かれていませんが、本質的な問題としては、繰り返しが最適化されるかどうかというより、関数として渡されたLAMBDA式のオーバーヘッドが最適化によって無くなるかどうかを調べないといけないですよねw

12月

KMRCLにつづいて、com.informatimago.common-lispを眺め始めたりしています。

また、CLAPにも参加してみました。

まとめ

ふりかえってみると、KMRCLまみれな一年でした。

全然関連した話題ではないですが、この3、4年位で眺めたところでは、今年は、新しくCommon Lispを始める人が増える傾向にあると思いました。

純粋関数型言語の擡頭で関数型言語を学ぶためにCommon Lisp/Schemeを選択する、という人は減っているとは思いますが、どういう理由でか地味に増えている気がします。

来年は、初心に返って誰得度の高い一年にしたいと思っています。

また、積み残しが沢山あるので、これらもこなせると良いなと思ったりしています。

来年も続けるであろうこと

  • Shibuya.lisp 運営
  • 逆引きCL運営
  • cddddr.org (みんなのLISPサーバ)運用
  • common-lisp-users.jp 運用

やりたいと思ってずっと積み残っているもの

  • 家の積読LISP本完読
  • Symbolicsのマニュアル読破
  • JLUGサイト改善
  • みんなでLISPを勉強するブログ
  • オンライン勉強会復活
  • L-99完遂
  • Getting Started in *Lisp (*Lispのチュートリアル)完遂
  • CLで学ぶ「プログラミングGauche」 完遂
  • AMOPの勉強
  • ObjectLispがANSI CLで動くようにする
  • CommonObjectsがANSI CLで動くようにする
  • INTERLISPで遊ぶ

2010-12-29

*macroexpand-hook*の使い道

| 19:26 | *macroexpand-hook*の使い道 - わだばLisperになる を含むブックマーク はてなブックマーク - *macroexpand-hook*の使い道 - わだばLisperになる

以前から、*macroexpand-hook*ってどんな使い道があるのだろうかと謎に思っていたのですが、Spice Lisp(TOPS-10 CL)のソースを眺めていて、macromemoというファイルを発見し、その中で*macroexpand-hook*が使われているのを見付けました。

マクロ展開関数の引数が2つのようなので、ANSI CL的に3つに揃えてみると、

(defun memoize-macro-call (expander expression env)
  "Replaces the call to a macro in Expression with a call to the expanded form
  with magic stuff wrapped around it."
  (let ((expansion (funcall expander expression env)))
    (if (eq (car expression) '*macroexpansion*) nil  ; "unless" is a macro...
	(displace expression (list '*macroexpansion* expansion
				   (cons (car expression) (cdr expression)))))
    expansion))

(defun displace (x y)
  "Replaces the CAR and CDR of X with the CAR and CDR of Y, returning the
  modified X."
  (rplaca x (car y))
  (rplacd x (cdr y)))

(defmacro *macroexpansion* (expansion original)
  (declare (ignore original))
  expansion)

(setq *macroexpand-hook* 'memoize-macro-call)

こんな感じになります。

動作させてみると、

;; 下準備
(defmacro foo (x)
  `(progn ,x))

(defmacro bar (y)
  `(progn ,y (foo 42)))

;; フックを設定
(setq *macroexpand-hook* 'memoize-macro-call)

(defparameter *expr* (copy-tree '(bar 7)))

(macroexpand *expr*)
;=> (PROGN 7 (*MACROEXPANSION* (PROGN 42) (FOO 42)))
;   T

*expr*
;=> (*MACROEXPANSION* (PROGN 7 (*MACROEXPANSION* (PROGN 42) (FOO 42))) (BAR 7))

;; 通常に戻す
(setq *macroexpand-hook* 'funcall)

(defparameter *expr* (copy-tree '(bar 7)))

;; 破壊的に書き変わっているので再度定義
(defmacro foo (x)
  `(progn ,x))

(defmacro bar (y)
  `(progn ,y (foo 42)))

(macroexpand *expr*)
;=> (PROGN 7 (FOO 42))
;   T

*expr*
;=> (BAR 7)

MacLISP等には、マクロ関係の機能で、displaceというのがあり、都度マクロを展開するのではなく、一度展開したものは、前の結果に置き換え、というものがあったようです。(ちなみに古いコードが残っているMaximaにもあります)

上記のコードは、実際の動作が掴みにくいのですが、一度展開されると同じものが返っているのが分かります。

現在は、コンパイラ指向の処理系が多いので効果は薄そうで、むしろ副作用の方が気になりますが、インタプリタでは有効なテクニックだったりしたのかもしれません。はっきりしたことは分かりませんが…。

マクロのメモ化も面白いと思って良くあるタイプのハッシュテーブルを使ったものに書き換えてみようかなとも思いましたが、引数の扱いはどうしたもんかということで頓挫しました。

日常LISP (3) 常用シェルをCLISPに その2

| 11:41 | 日常LISP (3) 常用シェルをCLISPに その2 - わだばLisperになる を含むブックマーク はてなブックマーク - 日常LISP (3) 常用シェルをCLISPに その2 - わだばLisperになる

シェルをCLISPにしてみる実験の経過報告。

  • まだ全部をCLISPにする、というのは辛い
  • パイプの問題をどうするか
  • プログラミングが簡単にできるので、部分的には、既存のシェルより楽になるところもある
  • やっぱりEmacsのシェルモードから入力すると楽
  • 履歴機能をもう少し充実させたい

といったところです。

改善点は、

  • 括弧/ダブルクォートの対を簡単に入力できるようにした
  • ユーティリティ関数を定義している

というところです。

括弧の入力支援については、

.inputrcに

"\eL": "()\C-b"
"\e\"": "\"\"\C-b"

というようなものを追加しました。

m-"とで、""が入力され、m-sh-Lで()が入力されます。括弧の方はちょっとイレギュラーですが、"("が遠いのでこういう風にしてみました。

また、Emacsのシェルモードで使うのに便利なように、

;; Emacs
(define-key shell-mode-map [(meta ?c)]
  (defun insert-\#\[\] ()
    (interactive)
    (insert "#[]")
    (backward-char)))

こんなのも定義してみました。

ユーティリティ関数については、

;; swank起動
(defun swank (&key (lisp :sbcl))
  (case lisp
    (otherwise #[/lisp/swank-sbcl-1.0.38])))

;; capistranoでデプロイ
(defun cap-staging (name)
  (prog1 (run-program "/home/foo/bin/cap-staging" ;; 既存のシェルスクリプト
                      :arguments (list (string-downcase name)))
         (princ #\Bell)
         (run-program "mpg123" :ARGUMENTS '("/home/foo/sounds/eudora-sound.mp3"))
         (run-program "firefox" :ARGUMENTS (list (case name
                                                   (:project-foo "/var/tmp/deployfinish.html")
                                                   (otherwise "http://unicodesnowmanforyou.com/"))))))

;; ssh
(defun foo ()
  #[ssh foo])

;; IE6マシンに接続
(defun ie6 ()
  #[xvncviewer 192.168.1.6])

という非常にどうでも良いものばかりをずらずら定義していますが、割と便利です。

関数を定義するとファイルに書き出されるようにするともっと便利かもしれません。対話環境については、Interlispの環境がヒントになる気がしたのでちょっと真似してみたいと思っています。

2010-12-27

C.I.CLを眺める(3) ENSURE-CIRCULAR

| 00:15 | C.I.CLを眺める(3) ENSURE-CIRCULAR - わだばLisperになる を含むブックマーク はてなブックマーク - C.I.CLを眺める(3) ENSURE-CIRCULAR - わだばLisperになる

今回は、C.I.CLのlist.lispからENSURE-CIRCULARです。

名前からして循環リストを作成するものというのが分かります。定義は、

(defun ensure-circular (list)
  "
If list is not a circular list, then modify it to make it circular.
RETURN: LIST
"
  (if (proper-list-p list)
      (setf (cdr (last list)) list)
      list))

で、前に定義したPROPER-LIST-Pを使い引数が真正リストかどうかをチェックし、真正リストでない場合は、引数をそのまま返しています。

動作は、

(import 'com.informatimago.common-lisp.list:ensure-circular)

(setq *print-circle* 'T)

(ensure-circular '(1 2 3))
;=> #1=(1 2 3 . #1#)

(ensure-circular '(1 . 2 ))
;=> (1 . 2 )

というところ

2010-12-23

日常LISP (2) 常用シェルをCLISPに

| 22:09 | 日常LISP (2) 常用シェルをCLISPに - わだばLisperになる を含むブックマーク はてなブックマーク - 日常LISP (2) 常用シェルをCLISPに - わだばLisperになる

以前から、CLISPをシェル代わりに使うというのは知っていましたが、さすがになかなか踏み切れませんでした。

しかし、今日急に、男は度胸!なんでもためしてみるのさ、という気持ちになったので、さっそく/etc/shellsにclispを登録して、chsh clispしてみました。

自分の場合、上のドキュメントにある、Step 3は必要なさそうなので飛しましたが、シェルとして使う上での肝は、Step 5: set up the reader macroかと思います。

リーダーマクロを設定して、

#[ls]
(RUN-PROGRAM "ls" :ARGUMENTS 'NIL)

のようなものに展開させます。

この設定をしないとコマンドがかなり実行しにくいと思うので必須でしょう。

これでも、#[]を入力するのが面倒なのですが、次の

Step 6: set up the readline shortcutの設定もしておけば、M-cで、#[]が入力されるので、コマンドを実行する程度ならば、それなりに使えるようになります。

CLISPは軽快なのでscreenなどと併用しても普通のシェルのようにサクサク開けます。これは結構意外でした。

補完や履歴など、まだまだ通常のシェルには及びませんが、しばらく使ってみたいと思います。

2010-12-21

日常LISP (1) ファイル内の文字列置換

| 23:34 | 日常LISP (1) ファイル内の文字列置換 - わだばLisperになる を含むブックマーク はてなブックマーク - 日常LISP (1) ファイル内の文字列置換 - わだばLisperになる

とにかく普段からLISPを使っていこうという、有意義なのかどうか分からない試みの記録。

日々遭遇するちょっとした仕事をできる限りCommon Lispで処理し、その感想をつらつらとまとめます。

できそうではあったけれど、手間や環境が原因でシェルスクリプト等に逃げてしまったものは、メモしておいて次回の対策を練ってみます。

さて、今日は、sedでできそうな仕事をCLで処理しました。

以前、職場のブログに書いてしまったネタとかぶる気がしますが、まあ良しとします。

(defun run ()
  (let ((suf "_removeme_"))
    (iterate ((file (scan (directory "/tmp/foo/**/*.html"))))
      (let ((nfile (format nil "~A.~A.htm" file suf)))
        (with-< (in file)
          (with-> (out nfile)
            (sed "<!-- ここからですよ -->"
                 "<!-- ここまでですよ -->"
                 "置換する内容ですよ
2行目ですよ
3行目ですよ"
                 :in in
                 :out out)))
        (rename-file nfile file)))))
;;
(run)

作業内容は、

  1. あるディレクトリ以下のHTMLファイル全部を開き
  2. 「ここから〜ここまで」を「置換する内容ですよ」で置換
  3. 置換した内容で上書き

という内容です。

実行は、SLIME上から実行します。

使っているライブラリは、

  1. series(iterate、scan)
  2. 俺関数

です。

俺関数ですが、

  1. WITH-<、WITH->はWITH-OPEN-FILEをちょっと加工したもので、入力と出力専用です。(WITH->はUnix風に上書き基本です。)
  2. SEDはsed風な動きをするだけで全然sedじゃないですが良いんです。

というところです。

おすすめポイントですが、細かいところは処理系依存のようですが、DIRECTORY(というかCLのパス名)は、**/*.htmlというzshのように再帰的に表記ができます。

これとENSURE-DIRECTORIES-EXISTを組み合せると結構便利だったりします。

気持ち的に負けてるなと感じるポイントは、パス周りを文字列として扱っているところですが、色々面倒なので割り切ってます。

2010-12-19

C.I.CLを眺める(2) PROPER-LIST-P

| 20:02 | C.I.CLを眺める(2) PROPER-LIST-P - わだばLisperになる を含むブックマーク はてなブックマーク - C.I.CLを眺める(2) PROPER-LIST-P - わだばLisperになる

今回は、C.I.CLのlist.lispからPROPER-LIST-Pです。

名前からして真正リストかどうかを判定するもののようですが、定義は、

(defun proper-list-p (object)
  "
RETURN: whether object is a proper list
NOTE:   terminates with any kind of list, dotted, circular, etc.
"
  (labels ((proper (current slow)
             (cond ((null current)       t)
                   ((atom current)       nil)
                   ((null (cdr current)) t)
                   ((atom (cdr current)) nil)
                   ((eq current slow)    nil)
                   (t                    (proper (cddr current) (cdr slow))))))
    (and (listp object) (proper object (cons nil object)))))

となっています。

SRFI-1で言えば、proper-list?ですが、循環リストを検出するために、properというローカル関数を定義して使っているようです。

動作は、

(import 'com.informatimago.common-lisp.list:proper-list-p)

(proper-list-p ())
;=> T

(proper-list-p 'a)
;=> NIL

(proper-list-p '(a))
;=> T

(proper-list-p '(a . b))
;=> NIL

(proper-list-p '#0=(even odd . #0#))
;=> NIL

というところ。

逆引きCommon Lispに記事を寄稿してくれる方募集

| 18:58 | 逆引きCommon Lispに記事を寄稿してくれる方募集 - わだばLisperになる を含むブックマーク はてなブックマーク - 逆引きCommon Lispに記事を寄稿してくれる方募集 - わだばLisperになる

あったらそれなりに便利かもしれない、ということで開始された逆引きCommon Lisp(並びにScheme/Clojure)ですが、いつの間にやら開始から2年となりました。

自分は、地味にでも記事を増やしたいなと思っている一人ですが、記事を直接WiLiKiに記述する以外にも既存のブログエントリーから記事を募ってみるのはどうだろうとふと思いました。

逆引きCLの編集方針と、ライセンスに同意して頂ける方、という制限がついてしまうのですが、寄稿しても良いよ!という方は、このブログのコメントででも教え頂けると嬉しいです。

教えて頂いたドキュメントを自分が移植したいと思います(もちろん直接転載して頂いてもOKです)

編集方針: 編集に関する基本方針

ライセンス: ライセンスについて

ちなみに、Googleドキュメントのフォーム機能が便利そうだったので、記念にアンケートを作成してみました。

逆引きCLについて何かありましたら是非ご意見下さい。

2010-12-18

MAP系の関数でスペシャルフォームを渡す

| 18:21 | MAP系の関数でスペシャルフォームを渡す - わだばLisperになる を含むブックマーク はてなブックマーク - MAP系の関数でスペシャルフォームを渡す - わだばLisperになる

TAOでは、マクロもFUNCALLできるのですが、Common Lispでは、MAP系の関数には、スペシャルフォームやマクロは通常渡せません。

どうしても、こういうことをしたい、という場合は、マクロにして内部を解析し、MAP系関数の見た目で使えるように仕立てる、というのはそれなりにできそうです。

しかし、この方法だとそのMAP系関数をFUNCALLできないという問題があります。

別にそれで困ることはないのですが、ふと実はコンパイラマクロでできたりするんじゃないかと思ったので無駄に試行錯誤してみました。

とりあえずmy-mapcarを作成(関数)

(defun my-mapcar (fn &rest lists)
  (apply #'mapcar fn lists))

コンパイラマクロを付ける

(define-compiler-macro my-mapcar (fn &rest lists)
  (if (or (equal ''cl:and fn)
          (equal ''cl:or fn)
          (equal ''cl:progn fn))
      (let* ((gs (mapcar (lambda (x)
                           (declare (ignore x))
                           (gensym "VAR-"))
                         lists))
             (fors (mapcan (lambda (g li) (list :for g :in li))
                           gs
                           lists)))
        `(loop ,@fors :collect (,(eval fn) ,@gs)))
      `(mapcar ,fn ,@lists)))

コンパイラマクロはコンパイルしないと効かないので対策

ボディをコンパイルするWITH-COMPILEを作成(この時点で既に脱線している気がする)

(defmacro with-compile (&body body)
  `(funcall (compile nil (f0 ,@body))))

動作を見てみる

(my-mapcar #'list
           '(1 2 3 4)
           '(nil nil nil)
           '(t t t t t))
;=> ((1 NIL T) (2 NIL T) (3 NIL T))

(with-compile
  (my-mapcar 'and
             '(1 2 3 4)
             '(nil nil nil)
             '(t t t t t)))
;=> (NIL NIL NIL)

(with-compile
  (my-mapcar 'or
             '(1 2 3 4)
             '(nil nil nil)
             '(t t t t t)))
;=> (1 2 3)

(with-compile
  (my-mapcar 'progn
             '(1 2 3 4)
             '(nil nil nil)
             '(t t t t t)))
;=> (T T T)

上の例なら動くけれどそもそも高階関数として使いたいのではなかったか。

ということで、

applyに細工して問題を先送り

(sb-ext:without-package-locks
  (define-compiler-macro apply (&whole form function arg farg)
    (if (or (equal '(quote my-mapcar) function)
            (equal '(function my-mapcar)
                   function))
        (if (symbolp farg)
            `(my-mapcar ,arg ,@farg)
            `(my-mapcar ,arg ,@(mapcar (f_ (cons 'quote (list _)))
                                       (eval farg))))
        form)))
(with-compile
  (apply #'my-mapcar
         'and
         '((1 2 3 4)
           (nil nil nil)
           (t t t t t))))
;=> (NIL NIL NIL)

(with-compile
  (apply #'my-mapcar
         'and
         (list '(1 2 3 4)
               '(nil nil nil)
               '(t t t t t))))
;=> (NIL NIL NIL)

(let ((arg (list '(1 2 3 4)
                '(nil nil nil)
                '(t t t t t))))
  (with-compile
    (apply #'my-mapcar
           'and
           arg)))
;=> ((1 2 3 4) (NIL NIL NIL) (T T T T T)) ; うーん、この問題どうしよう…

なにやら色々ややこしい…。

FUNCALLだったら大丈夫だったりしないだろうか、ということで、

FUNCALLも試してみる

(sb-ext:without-package-locks
  (define-compiler-macro funcall (&whole form function arg farg)
    (if (or (equal '(quote my-mapcar) function)
            (equal '(function my-mapcar)
                   function))
        `(my-mapcar ,arg ,@farg)
        form)))
(let ((x '(1 2 3 4))
      (y '(nil nil nil))
      (z '(t t t t t)))
  (with-compile
    (funcall #'my-mapcar 'or x y z)))
;=> (1 2 3)

関数に渡される引数の問題はAPPLYより簡単そう。

しかし、

(let ((x '(1 2 3 4))
      (y '(nil nil nil))
      (z '(t t t t t))
      (f #'my-mapcar))
  (with-compile
    (funcall f 'or x y z)))
;>>> The function OR is undefined.

こういうのは駄目。

結論

結局、どこかに皺寄せがくるようです。

2010-12-15

NILのマニュアル発見!

| 00:21 | NILのマニュアル発見! - わだばLisperになる を含むブックマーク はてなブックマーク - NILのマニュアル発見! - わだばLisperになる

今日ふとしたきっかけから自分が長らく知りたいなと思っていたLISP方言のNILのマニュアルを発見することができました。

場所は、コンピュータ関係の貴重な資料を集めている、Computer History MusiumのSoftware Preservation Groupのページからなのですが、どうも最近公開されたようです。

ざっとNILを紹介すると、NIL*1は、New Implementation of Lispの略で、70年代後半から80年代前半にかけて、Lispマシンのような専用マシンではなく当時発表されたVAXのような廉価(専用マシンに比べ)な汎用マシンで動くLISPが求められていたのですが、そんなVAXをターゲットにMacLISP系の方言として実装が開始されました。

稼動することが期待されていた主なアプリケーションはMacsymaで、ターゲットユーザーもMacsymaのユーザーだったようですが、それ故、演算に強いことが求められていたようです。

そんなこんなで開発がスタートしたNILですが、82年位からCommon Lisp策定の動きが出てきます。

いままでネット上で入手できる資料では、Common Lispとの関係がいまいち不明だったのですが、このマニュアルを読む限り途中から、NILは、Common Lispの方言として開発が進められたようです。

このマニュアルが出た時期は、1983/2月〜1983/12月なのですが、Common Lispは1984年に仕様が固まったので、Common Lisp策定よりまえに方言があったということになるのが面白いところ。

KCLも1983年から開発がスタートしているようですし、Spice Lispも既に開発されているしで、仕様が出る前に色々な処理系があったようです。

方言というからには色々違ってくるところがあると思うのですが、1983年12月のマニュアルではほぼCommon Lispのスーパーセットになっているようです。

機能としては、Lispマシンのように、ユーザーが拡張可能なLOOPマクロ、FORMATに加え、オブジェクト指向システムとしては、Flavorsがあるという感じです。

STEVEというNILで書かれたEmacsがあったり、基本的になんでもユーザーが拡張できるようになっていてフリーダム。標準で妙な機能もあったりしてMITのハッカーテイストが溢れているなあと思いました。

ということで一人興奮しつつ、早速NILのマニュアルを眺めていたのですが、メモがわりにTwitterでつぶやいていたのでブログにまとめて置くことにしました。誰得ですが。

  • g177564: livlisに冗談でNILについての本を登録しようとしたら、最近公開されてた! やった! software preservation group凄い! http://bit.ly/gGg6hI
  • g177564: うーん、でも83年のマニュアル眺めるとNILはCLの方言ってことになってるなー。ちょっと残念
  • g177564: でも、letが分配束縛に対応してたりはするな >nil
  • g177564: LispM lispと同じく、macroもある様子。あと、progwがある。でも仕様がちょっと違う気がする。progwqとprogwfってなんだ。 >NIL
  • g177564: LispMと同じくlexpr-funcallがある。dovectorというのがあった。doは古いスタイルもサポート。(do var init step endtest body)という形式 > NIL
  • g177564: catchとthrowはCLと同じ形式で、古い形式は、*catchと*throwになっている様子。多分これはLispM lispと逆だと思う。values-vectorってのがある。NILではvectorを良く使うらしい。 >NIL
  • g177564: multiple-valueという名前でmultiple-value-seqがあるLispM lispと同じ。get-propertiesというのはなんぞ。sortcar、memq、samepnamep、はMacLISPコンパチ >NIL
  • g177564: (gensym 8)という仕様を初めて知った。へー。
  • g177564: CLで定義されてない便利関数として、symbolconcとpackage-symbolconcがあった。(symbolconc 'foo '- 5)=> foo-5(多分) >NIL
  • g177564: 伝統のadd1 sub1 greaterp timesがあった。 fixnum専用で +& *&などがある。double floatは、+$。vector専用にvref、make-vector。to-stringもある。
  • g177564: hashtableで、string=とstring-equalが使える。パッケージの仕組みは独自のものを持っていたらしいが破棄されたみたい >NIL
  • g177564: defstruct回りに変なものが沢山ある気がする。:predicateでマクロみたいな形式で関数が定義できる >NIL
  • g177564: NILのLOOPはCLtL1の単純LOOPではなくて、LispMのLOOPが載っている様子。ANSI CLと違ってdefine-loop-sequence-pathによってユーザーが拡張可能。
  • g177564: いや、loop pathを定義する最も汎用的なものは、define-loop-pathらしい。 >NIL
  • g177564: formatもLispMと同じくANSI CLよりずっと魔窟。~\foo\で複数文字も受け付ける気でいたらしい。さらにフォーマット指示子をdefine-format-opでユーザーが拡張できる。
  • g177564: allfilesでディレクトリ以下の全ファイルが取れる。mapallfilesというのもある。>NIL
  • g177564: ;; -*-Mode:Lisp; -*- のようなものがファイルの属性としてファイルシステムの項目で定義してある。へー。 >NIL
  • g177564: 19.8.7.2 RMS and Related Hacking なんぞこの章www >NIL
  • g177564: なるほど、VMSにRMSというのがあったのか >NIL
  • g177564: CGOLのreadtableが用意されているらしいw >NIL
  • g177564: who-calls、whereisがある。describeのようなexhibitがある。これはオブジェクトを対話的に編集できるらしい >NIL
  • g177564: timerというのがある。(timer #'cons 100 #(a b))でconsを百回実行するらしい。apply的だけどvectorも引数として指定できるらしい >NIL
  • g177564: timeパッケージに便利そうなものが色々定義されているけど、time:moonphaseとか使うのだろうかw >NIL
  • g177564: おお!、昔のMacLISPとかのファイルのヘッダに良く書かれているFM +2D.3H.29M.57S.とかいう文字は、月の満ち欠けについてだったのか。なんで記録してるんだろうw >NIL
  • g177564: .@garaemon さらにtime:print-moonphaseでプリティプリントされた結果が印字できるようですw
  • g177564: time:last-sunday-in-aprilと、time:last-sunday-in-octoberって何のためにあるの?w >NIL
  • g177564: 23.5.8 Brain Damageという章があるw >NIL
  • g177564: Emacs系のSTEVEっていうエディタが標準で付いてるらしい >NIL
  • g177564: STEVEはNILで書かれたEmacsらしい。 >NIL
  • g177564: Bolioモードがある。多分このマニュアルもbolioで書かれている気がする >NIL
  • g177564: へー、LL modeというemacs のinteraction-modeみたいなのがある >NIL
  • g177564: へー、c-m-w append-next-killとか始めて知った。こういう古いマニュアルを読んでEmacsのコマンドを発見することが多いw
  • g177564: STEVEのコマンド名は、Zmacsみたいに、Foo Bar Baz形式ではなくてEmacs風にFoo-Bar-Bazらしい >NIL
  • g177564: LispMのように、パッチ機構がある。load-patchesでパッチを読み込んで当てる。si:new-patch-systemでモジュールに対してのパッチを作成する模様 >NIL
  • g177564: 述語の組み合わせを単純にするという機構がある様子。(and c d (or a b)) => (or (and a c d) (and b c d)) 便利なんだろうか >NIL
  • g177564: Mini-MYCINというのがデモで付いてくる様子 >NIL
  • g177564: VMSの機能により、si:defsyscallを使えば、BASIC、C、Pascal、PL/1、BLISS etcと連携できるらしい >NIL
  • g177564: 命名規則は、CLと同じ様子。システムで定義済の変更しても良い変数は、*foo-bar-baz*、定数は、foo-bar-bazという解釈らしい >NIL
  • g177564: やっと339ページ眺め終った >NIL CLの方言ということだけど、CLtLの決定は、1984年で、NILは1983年なのでCLは標準より先に方言があったということになるんだろうか。
  • g177564: @seiji1976 なるほど、これは羨しい機構ですねー。VMSのCLである VAX LISPもVMSでは同じ感じだったようです。
  • g177564: @garaemon ですねー、これ良くマクロ定義で使いますよね >symbolconc
  • g177564: @komagata なるほど昔は結構ハッカー的にはポピュラーだったんですかね。パッケージはtimeパッケージにまとまっているのですが多分9割方ふざけてるんだと思いますw。ファイルを保存すると多分勝手に更新されるんですよね
  • g177564: さっき眺めたNILのマニュアルより古いのを眺めたら真として、#tを定義していたらしい、NILと()も別物としていた様子。CLに合せてt nil = () にした様子。偽は、どうも#fではなくてnilっぽい
  • g177564: 文字表現もディスパッチマクロ文字だけどNILは、#2\a とかでフォントの種類を変更できたのかw CLtL1もそうだったんだろうか

*1:ちなみに、YaleのScheme系方言のTはこれをもじったらしいです

2010-12-12

ありがとう LISP365

| 20:09 | ありがとう LISP365 - わだばLisperになる を含むブックマーク はてなブックマーク - ありがとう LISP365 - わだばLisperになる

Advent Calendarを1年に拡大してみたら面白いんじゃないか、という非常に適当な思い付きから始めたLISP365ですが、本日ついに最終日となりました!

参加者は、16名。 12名の方にエントリーを書いて頂けました。

総エントリー数は456エントリー。

各人のエントリー数ですが、多い方から順に、

  1. g000001: 319エントリー
  2. sileさん: 59エントリー
  3. quekさん: 40エントリー
  4. kyanny/a666666さん: 9エントリー
  5. nitro_idiotさん: 9エントリー
  6. mori_devさん: 8エントリー
  7. tszさん: 4エントリー
  8. garaemonさん: 2エントリー
  9. makingさん: 2エントリー
  10. smegheadさん: 2エントリー
  11. takeokaさん: 1エントリー
  12. yad-ELさん: 1エントリー

という結果に。

エントリーを提供して頂いたみなさまありがとうございました!

集計してみて、言い出しっぺの私のエントリー数が365を越えなかったところにちょっとした幸せを感じますw

一年間途切れないようにするのは結構大変で、実際のところうっかりミスや登録もれでエントリーを書いていても4、5回はその日の24時までに登録できていません。

まあ、でもそんなこと誰も気にしてないので良いのかなと…。

次もなにかやってみたいなと考えたりはしています。

参加エントリー*1

【2009/12/12】 SLIMEに感動: g000001

【2009/12/13】 KMRCLを眺める (38) FIND-TREE: g000001

【2009/12/14】 Weblocks: quek

【2009/12/14】 アナフォリックDEFUNでバグに勝つる!: g000001

【2009/12/15】 KMRCLを眺める (39) FLATTEN: g000001

【2009/12/16】 KMRCLを眺める (40) REMOVE-KEYWORD: g000001

【2009/12/17】 KMRCLを眺める (41) REMOVE-KEYWORDS: g000001

【2009/12/18】 sheepleでオブジェクトを作る: tsz

【2009/12/19】 KMRCLを眺める (43) MAPPAPPEND: g000001

【2009/12/20】 KMRCLを眺める (43) MAPCAR-APPEND-STRING-NONTAILREC: g000001

【2009/12/20】 sheepleでディスパッチ: tsz

【2009/12/21】 KMRCLを眺める (44) MAPCAR-APPEND-STRING: g000001

【2009/12/22】 slime + auto-complete: tsz

【2009/12/23】 KMRCLを眺める (46) MAPCAR2-APPEND-STRING: g000001

【2009/12/24】 KMRCLを眺める (47) APPEND-SUBLISTS: g000001

【2009/12/25】 bit誌上でのTAO/ELISの連載「マルチパラダイム言語 TAO」公開!: g000001

【2009/12/25】 executor: tsz

【2009/12/26】 KMRCLを眺める (49) ALISTP: g000001

【2009/12/27】 KMRCLを眺める (50) UPDATE-ALIST: g000001

【2009/12/28】 KMRCLを眺める (51) GET-ALIST: g000001

【2009/12/28】 letを理解して年内に勝ち組Lisperになる: nitro_idiot

【2009/12/29】 KMRCLを眺める (52) (SETF GET-ALIST): g000001

【2009/12/30】 KMRCLを眺める (53) ALIST-PLIST: g000001

【2009/12/30】 [L-99]P02 (*) Find the last but one box of a list.: a666666

【2009/12/31】 KMRCLを眺める (54) PLIST-ALIST: g000001

【2010/01/01】 KMRCLを眺める (55) UPDATE-PLIST: g000001

【2010/01/01】 Common Lispで書き初め: smeghead

【2010/01/02】 KMRCLを眺める (56) UNIQUE-SLOT-VALUES: g000001

【2010/01/03】 KMRCLを眺める (57) PRINT-FILE-CONTENTS: g000001

【2010/01/03】 Lisp製Blogシステム「CategoL」リリース: makingx

【2010/01/04】 KMRCLを眺める (58) READ-STREAM-TO-STRINGC: g000001

【2010/01/05】 KMRCLを眺める (59) READ-FILE-TO-STRING: g000001

【2010/01/06】 [L-99]P03 (*) Find the K'th element of a list.: a666666

【2010/01/07】 Schemeにおけるリファクタリングのパターン: yad-EL

【2010/01/08】 KMRCLを眺める (61) READ-STREAM-TO-STRINGS: g000001

【2010/01/09】 KMRCLを眺める (62) READ-FILE-TO-STRINGS: g000001

【2010/01/10】 Shibuya.lisp に向けて Scheme コードバトンするのはどうか? (2): g000001

【2010/01/10】 [L-99]P04 (*) Find the number of elements of a list.: a666666

【2010/01/11】 P05 (*) Reverse a list.: a666666

【2010/01/11】 Schemeコードバトンに参加しました: g000001

【2010/01/12】 KMRCLを眺める (63) STREAM-SUBSTComments: g000001

【2010/01/13】 BWT : bzip2 : 修正版: sile

【2010/01/13】 MTF : bzip2: sile

【2010/01/14】 KMRCLを眺める (64) FILE-SUBST: g000001

【2010/01/15】 KMRCLを眺める (65) PRINT-N-CHARS: g000001

【2010/01/16】 長さ制限付きハフマン符号化 : 整理: sile

【2010/01/16】 Hunchentoot と Elephant の CLSQL バックエンド を使うとき: quek

【2010/01/17】 P06 (*) Find out whether a list is a palindrome.: a666666

【2010/01/17】 ハフマン符号化 : 整理: sile

【2010/01/18】 Xで良い: g000001

【2010/01/18】 ftype型宣言(sbcl) : 戻り値の型指定: sile

【2010/01/19】 KMRCLを眺める (67) INDENT-SPACES: g000001

【2010/01/19】 sbcl, apache, cgi, エラー: sile

【2010/01/20】 KMRCLを眺める (68) INDENT-HTML-SPACES: g000001

【2010/01/20】 列の分割: sile

【2010/01/21】 eLisp : Embedded Lisp: sile

【2010/01/21】 ABCLをソースからビルドするためのメモ ant編: g000001

【2010/01/21】 KMRCLを眺める (70) PRINT-ROWSComments: g000001

【2010/01/23】 一文字マクロ文字: sile

【2010/01/24】 関数のドキュメント: sile

【2010/01/24】 KMRCLを眺める (71) WRITE-FIXNUM: g000001

【2010/01/25】 KMRCLを眺める (72) NULL-OUTPUT-STREAM: g000001

【2010/01/26】 KMRCLを眺める (73) WITH-UTIME-DECODING: g000001

【2010/01/26】 KMRCLを眺める (74) IS-DST: g000001

【2010/01/18】 第1回 Scheme コードバトン (CL fork)に参加しました。: smeghead

【2010/01/28】 KMRCLを眺める (75) WITH-UTIME-DECODING-UTC-OFFSET: g000001

【2010/01/29】 KMRCLを眺める (76) WRITE-UTIME-HMS: g000001

【2010/01/30】 Macで最新のClojure(+contrib)を最速でインストール: nitro_idiot

【2010/01/30】 UbuntuでClojureからOpenCVを使えるようにする: nitro_idiot

【2010/01/31】 KMRCLを眺める (77) WRITE-UTIME-HMS: g000001

【2010/02/01】 Lispjobs.jpにCLerの募集が掲載!: g000001

【2010/02/02】 Leiningenでハローワールド: makingx

【2010/02/02】 Common Lisp でのクラスメソッド: quek

【2010/02/03】 KMRCLを眺める (78) WRITE-UTIME-HM-STREAM: g000001

【2010/02/04】 KMRCLを眺める (79) WRITE-UTIME-HM: g000001

【2010/02/05】 KMRCLを眺める (80) WRITE-UTIME-YMDHM-STREAM: g000001

【2010/02/06】 KMRCLを眺める (81) WRITE-UTIME-YMDHM: g000001

【2010/02/07】 KMRCLを眺める (82) WRITE-UTIME-YMDHM-STREAM: g000001

【2010/02/08】 KMRCLを眺める (83) WRITE-UTIME-YMDHM: g000001

【2010/02/09】 equal-case: sile

【2010/02/10】 KMRCLを眺める (84) COPY-BINARY-STREAM: g000001

【2010/02/11】 KMRCLを眺める (85) CANONICALIZE-DIRECTORY-NAME: g000001

【2010/02/11】 llvm : tutorial : lexer,parser: sile

【2010/02/12】 Gnu Common Lisp(GCL)/Kyoto Common Lisp(KCL)の最適化について: takeokas

【2010/02/12】 KMRCLを眺める (86) PROBE-DIRECTORYComments: g000001

【2010/02/13】 compute-effective-slot-definition の第三引数がリストであることの理由: quek

【2010/02/14】 KMRCLを眺める (87) DIRECTORY-TREE: g000001

【2010/02/15】 KMRCLを眺める (88) STRING-APPEND: g000001

【2010/02/16】 llvm : tutorial : code generation: sile

【2010/02/16】 KMRCLを眺める (89) LIST-TO-STRING: g000001

【2010/02/17】 llvm : tutorial : optimize: sile

【2010/02/17】 KMRCLを眺める (90) COUNT-STRING-WORDS: g000001

【2010/02/18】 KMRCLを眺める (91) POSITION-CHAR: g000001

【2010/02/19】 KMRCLを眺める (92) POSITION-NOT-CHAR: g000001

【2010/02/20】 KMRCLを眺める (93) DELIMITED-STRING-TO-LIST: g000001

【2010/02/21】 KMRCLを眺める LIST-TO-DELIMITED-STRING (94): g000001

【2010/02/22】 llvm : tutorial : jit: sile

【2010/02/22】 コムソート: sile

【2010/02/23】 KMRCLを眺める STRING-INVERT (95): g000001

【2010/02/24】 KMRCLを眺める STRING-TRIM-LAST-CHARACTER (96): g000001

【2010/02/25】 KMRCLを眺める NSUBSEQ (97): g000001

【2010/02/26】 KMRCLを眺める NSTRING-TRIM-LAST-CHARACTER (98): g000001

【2010/02/27】 KMRCLを眺める STRING-HASH (99): g000001

【2010/02/28】 KMRCLを眺める IS-STRING-EMPTY (100): g000001

【2010/03/01】 KMRCLを眺める STRING-SUBSTITUTE (101): g000001

【2010/03/02】 KMRCLを眺める IS-CHAR-WHITESPACE (102): g000001

【2010/03/03】 KMRCLを眺める IS-STRING-WHITESPACE (103): g000001

【2010/03/04】 KMRCLを眺める STRING-RIGHT-TRIM-WHITESPACE (104): g000001

【2010/03/05】 KMRCLを眺める STRING-LEFT-TRIM-WHITESPACE (105): g000001

【2010/03/06】 KMRCLを眺める STRING-TRIM-WHITESPACE (106): g000001

【2010/03/07】 KMRCLを眺める REPLACED-STRING-LENGTH (107): g000001

【2010/03/08】 KMRCLを眺める SUBSTITUTE-CHARS-STRINGS (108): g000001

【2010/03/09】 KMRCLを眺める ESCAPE-XML-STRING (109): g000001

【2010/03/10】 KMRCLを眺める MAKE-USB8-ARRAY (110): g000001

【2010/03/11】 KMRCLを眺める USB8-ARRAY-TO-STRING (111): g000001

【2010/03/12】 KMRCLを眺める STRING-TO-USB8-ARRAY (112): g000001

【2010/03/13】 KMRCLを眺める CONCAT-SEPARATED-STRINGS (113): g000001

【2010/03/14】 KMRCLを眺める ONLY-NULL-LIST-ELEMENTS-P (114): g000001

【2010/03/14】 KMRCLを眺める PRINT-SEPARATED-STRINGS (115): g000001

【2010/03/16】 KMRCLを眺める PREFIXED-FIXNUM-STRING (116): g000001

【2010/03/17】 KMRCLを眺める PREFIXED-FIXNUM-STRING (117): g000001

【2010/03/18】 KMRCLを眺める PREFIXED-INTEGER-STRING (118): g000001

【2010/03/19】 KMRCLを眺める INTEGER-STRING (119): g000001

【2010/03/20】 KMRCLを眺める FAST-STRING-SEARCH (120): g000001

【2010/03/21】 KMRCLを眺める STRING-DELIMITED-STRING-TO-LIST (121): g000001

【2010/03/22】 KMRCLを眺める STRING-TO-LIST-SKIP-DELIMITER (122): g000001

【2010/03/23】 Igo : Common Lisp版: sile

【2010/03/24】 KMRCLを眺める(123) STRING-STARTS-WITH: g000001

【2010/03/25】 KMRCLを眺める(124) COUNT-STRING-CHAR: g000001

【2010/03/26】 KMRCLを眺める(125) COUNT-STRING-CHAR-IF: g000001

【2010/03/27】 loop-finish: quek

【2010/03/27】 KMRCLを眺める(126) NON-ALPHANUMERICP: g000001

【2010/03/27】 KMRCLを眺める(127) HEXCHAR: g000001

【2010/03/29】 make-sequenceとmake-array: sile

【2010/03/30】 KMRCLを眺める(128) CHARHEX: g000001

【2010/03/31】 KMRCLを眺める(129) BINARY-SEQUENCE-TO-HEX-STRING: g000001

【2010/03/31】 『プログラミング Clojure』の「第4章 シーケンスと使ったデータの統合」を Common Lisp の SERIES でやってみる: quek

【2010/04/01】 配列スタック: sile

【2010/04/01】 Common Lisp で 1 を返す関数 lambda constantly *: quek

【2010/04/02】 Igo : sbcl-1.0.28, sbcl-1.0.37: sile

【2010/04/02】 :a: sile

【2010/04/03】 KMRCLを眺める(130) ENCODE-URI-STRING: g000001

【2010/04/04】 KMRCLを眺める(131) DECODE-URI-STRING: g000001

【2010/04/05】 KMRCLを眺める(132) URI-QUERY-TO-ALIST: g000001

【2010/04/06】 KMRCLを眺める(133) RANDOM-CHAR: g000001

【2010/04/07】 KMRCLを眺める(134) RANDOM-STRING: g000001

【2010/04/08】 KMRCLを眺める(135) FIRST-CHAR: g000001

【2010/04/09】 KMRCLを眺める(136) LAST-CHAR: g000001

【2010/04/10】 maphash-to-list: sile

【2010/04/10】 KMRCLを眺める(137) ENSURE-STRING: g000001

【2010/04/11】 (1)ELIS Common LispのGCフリーコーディング機能 : 実時間応用をねらいとして(1991): g000001

【2010/04/12】 KMRCLを眺める(138) STRING-RIGHT-TRIM-ONE-CHAR: g000001

【2010/04/13】 (2)マルチプロセッサLispマシンMacELIS IIのアーキテクチャ(1989): g000001

【2010/04/14】 KMRCLを眺める(139) REMOVE-CHAR-STRING: g000001

【2010/04/15】 (3)Tachyon Common LispのPA-RISCへの移植(1994): g000001

【2010/04/16】 KMRCLを眺める(140) STRING-STRIP-ENDING: g000001

【2010/04/17】 (4)Common Lispサブセットの試作(1986): g000001

【2010/04/18】 KMRCLを眺める(141) STRING-ELIDE: g000001

【2010/04/18】 Common Lisp から Yahoo の日本語形態素解析を使う: quek

【2010/04/19】 (5)Common Lisp言語処理系の64ビット化(2004): g000001

【2010/04/20】 KMRCLを眺める(142) STRING-MAYBE-SHORTEN: g000001

【2010/04/21】 (6)Common Lisp言語処理系による64ビット環境の評価(2006): g000001

【2010/04/22】 KMRCLを眺める(143) SHRINK-VECTOR: g000001

【2010/04/23】 (7)スーパコンピュータ(ベクトル計算機)のための並列Lispコンパイラ(1990): g000001

【2010/04/24】 KMRCLを眺める(144) LEX-STRING: g000001

【2010/04/25】 (8)Tachyon Common Lispにおけるウインドウ・インタフェース(1993): g000001

【2010/04/25】 マルチバイト文字列→ユニコード文字列: sile

【2010/04/26】 (9)TUPLE: SIMD型超並列計算のための拡張 Common Lisp(1994): g000001

【2010/04/27】 KMRCLを眺める(145) SPLIT-ALPHANUMERIC-STRING: g000001

【2010/04/28】 KMRCLを眺める(146) COLLAPSE-WHITESPACE: g000001

【2010/04/29】 (10)CLOSによる作曲支援及び音響合成の統合環境:IRCAM OpenMusicの今日: g000001

【2010/04/30】 適当な画像ファイルを用意する: quek

【2010/05/01】 KMRCLを眺める(147) STRING->LIST: g000001

【2010/05/02】 (11)Common Lisp検証システム(1993): g000001

【2010/05/03】 コンパイルすると何故か異様にファイルサイズが大きくなる関数: sile

【2010/05/03】 KMRCLを眺める(148) TRIM-NON-ALPHANUMERIC: g000001

【2010/05/04】 (12)Lisp システムにおけるデバッギング・ツール(1979): g000001

【2010/05/05】 creole : 文字列/バイト列変換: sile

【2010/05/05】 KMRCLを眺める(149) SUBSTITUTE-STRING-FOR-CHAR: g000001

【2010/05/05】 端末操作: sile

【2010/05/06】 common lispで文字列処理用の関数を書くときの難点: sile

【2010/05/07】 StumpWMの日々 (3): g000001

【2010/05/08】 (asdf-install:install ライブラリ名)でインストール可能にする方法: sile

【2010/05/08】 StumpWMの日々 (4): g000001

【2010/05/09】 KMRCLを眺める(150) ESCAPE-BACKSLASHES: g000001

【2010/05/09】 sbclで文字列を効率的に扱う場合の型: sile

【2010/05/10】 (13)Cambridge Lisp(1985): g000001

【2010/05/11】 KMRCLを眺める(151) ESCAPE-BACKSLASHES: g000001

【2010/05/12】 引数の型チェックの有無を使用者に選択させる(sbcl): sile

【2010/05/12】 SLIMEとLTDを使ってCLのコードをDylanに変換して表示する: g000001

【2010/05/12】 KMRCLを眺める(152) HTML/XML constants: g000001

【2010/05/14】 (14)浅い束縛による動的スコープ変数が存在する時の末尾再帰呼び出し(2000): g000001

【2010/05/15】 KMRCLを眺める(153) USER-AGENT-IE-P: g000001

【2010/05/15】 charseq: sile

【2010/05/15】 Common Lisp で SandS: quek

【2010/05/16】 (15)LISP(プログラミング言語の最近の動向)(1981): g000001

【2010/05/17】 StumpWMの日々 (5) 〜オフライン時のスタートアップ〜: g000001

【2010/05/18】 KMRCLを眺める(154) BASE-URL!: g000001

【2010/05/19】 (16)何故, LISPに基づいたコマンド言語がよいのか(1981): g000001

【2010/05/19】 簡易外部リンククローラ: sile

【2010/05/20】 LOUDS++(1): sile

【2010/05/20】 UranusをANSI Common Lispで動かそう: g000001

【2010/05/21】 LOUDS++(2): rankとselect: sile

【2010/05/21】 KMRCLを眺める(155) MAKE-URL: g000001

【2010/05/22】 (17)Tachyon Common LispのSPARCへの移植(1993): g000001

【2010/05/23】 みんなでLISPのウェブアプリを作る場所が欲しい: g000001

【2010/05/24】 KMRCLを眺める(156) DECODE-URI-QUERY-STRING: g000001

【2010/05/25】 (18)CommonLoops: Common Lispオブジェクト指向機能の標準化原案(1986): g000001

【2010/05/26】 KMRCLを眺める(157) SPLIT-URI-QUERY-STRING: g000001

【2010/05/27】 (19)ELIS Common Lispのマルチプログラミング機能(1989): g000001

【2010/05/28】 (20)TAOのパッケージシステム(1994): g000001

【2010/05/29】 Common Lisp で HTML のテンプレートエンジンを作るなら: quek

【2010/05/29】 KMRCLを眺める(158) IF*: g000001

【2010/05/30】 Getting Started in *LISP (24): g000001

【2010/06/01】 LOUDS++(3): LOUDS++: sile

【2010/06/02】 KMRCLを眺める(159) MEMO-PROC: g000001

【2010/06/03】 (22)LISP 構造エディタ(エディタ)(1984): g000001

【2010/06/04】 KMRCLを眺める(160) MEMOIZE: g000001

【2010/06/05】 Getting Started in *LISP (25): g000001

【2010/06/06】 みんなでLISPのウェブアプリを作る場所が欲しい (2): g000001

【2010/06/07】 (23)新ELISのプログラム開発支援系(1992): g000001

【2010/06/08】 KMRCLを眺める(161) DEFUN-MEMO: g000001

【2010/06/09】 (24)KCl(Kyoto Common Lisp)(1984): g000001

【2010/06/10】 KMRCLを眺める(162) _F: g000001

【2010/06/11】 リストの反転: sile

【2010/06/11】 Getting Started in *LISP (26): g000001

【2010/06/12】 動的オブジェクト指向言語Dylan(1995): g000001

【2010/06/13】 KMRCLを眺める(163) COMPOSE: g000001

【2010/06/14】 LOUDS++(4): bit-vector: sile

【2010/06/15】 キュー: sile

【2010/06/16】 KMRCLを眺める(164) CL-VARIABLES: g000001

【2010/06/17】 (27)マルチパラダイム言語処理系MCによるプログラム開発(1990): g000001

【2010/06/18】 Getting Started in *LISP (27): g000001

【2010/06/19】 KMRCLを眺める(165) CL-FUNCTIONS: g000001

【2010/06/20】 (28)電子メール討論 : Common Lisp における実例(1987): g000001

【2010/06/21】 KMRCLを眺める(166) CL-SYMBOLS: g000001

【2010/06/22】 (29)AIP-LISP : (1)レジスタ・アロケータ(1989): g000001

【2010/06/23】 KMRCLを眺める(167) STRING-DEFAULT-CASE: g000001

【2010/06/24】 日米並列Lispワークショップに参加して(1989): g000001

【2010/06/25】 KMRCLを眺める(168) CONCAT-SYMBOL-PKG: g000001

【2010/06/26】 CLで学ぶ「プログラミングGauche」 (9.8): g000001

【2010/06/27】 Githubを利用して普段のLISP開発環境を晒してみたらどうか: g000001

【2010/06/28】 AUTO-IMPORT: g000001

【2010/06/29】 KMRCLを眺める(169) CONCAT-SYMBOL: g000001

【2010/06/30】 引数の順番を覚えられないならELTを使えば良いじゃない!: g000001

【2010/07/01】 KMRCLを眺める(170) ENSURE-KEYWORD: g000001

【2010/07/02】 (31)第二回 Lisp コンテスト: g000001

【2010/07/03】 KMRCLを眺める(171) ENSURE-KEYWORD-UPCASE: g000001

【2010/07/04】 (32)Concurrent Common LISP(1988): g000001

【2010/07/05】 common-lisp-user.jp 稼動させました: g000001

【2010/07/06】 KMRCLを眺める(172) ENSURE-KEYWORD-DEFAULT-CASE: g000001

【2010/07/07】 KMRCLを眺める(173) SHOW-VARIABLES: g000001

【2010/07/08】 KMRCLを眺める(174) SHOW-FUNCTIONS: g000001

【2010/07/08】 DAWG: sile

【2010/07/09】 KMRCLを眺める(175) SHOW: g000001

【2010/07/10】 (34)TAO/ELISのUNIXへの移植(1995): g000001

【2010/07/11】 DAWG(2): ID付け: sile

【2010/07/11】 teepeedee2 と Google Map と Parenscript: quek

【2010/07/12】 (34)TAO LISPについて(1979): g000001

【2010/07/13】 (35)LISPマシンELISの基本設計(1980): g000001

【2010/07/14】 DAWG(4-1): 完全ハッシュ関数: sile

【2010/07/15】 (36)LispマシンELISの開発環境(1982): g000001

【2010/07/16】 Common Lispで高階関数クイズ: nitro_idiot

【2010/07/16】 (37)A Principle of New Programming Environment(1981): g000001

【2010/07/17】 DAWG(4-2): MPHF: sile

【2010/07/18】 (37)LispマシンELIS上の新Lisp TAO(1982): g000001

【2010/07/19】 (39)LispマシンELIS上の新Lisp TAO(1982): g000001

【2010/07/20】 KMRCLを眺める(176) FIND-TEST-GENERIC-FUNCTIONS: g000001

【2010/07/21】 KMRCLを眺める(177) RUN-TESTS-FOR-INSTANCE: g000001

【2010/07/22】 (40)LispマシンELISのアーキテクチャ -メモリレジスタの汎用化とその効果- (1983): g000001

【2010/07/23】 KMRCLを眺める(178) GETPID: g000001

【2010/07/24】 KMRCLを眺める(179) FILE-SIZE: g000001

【2010/07/25】 (41)NUE/TAO/ELISのOS的側面(1984): g000001

【2010/07/26】 ABCL/1 ABCL/R2をビルドする: g000001

【2010/07/27】 KMRCLを眺める(180) COMMAND-OUTPUT: g000001

【2010/07/28】 KMRCLを眺める(181) RUN-SHELL-COMMAND: g000001

【2010/07/29】 KMRCLを眺める(182) DELETE-DIRECTORY-AND-FILES: g000001

【2010/07/30】 (42)TAOにおける代入計算機構(1985): g000001

【2010/07/31】 (43)Object - Oriented Programming in Lisp(1983): g000001

【2010/08/01】 (44)Common Lispについて(1985): g000001

【2010/08/02】 ユニコード正規化: sile

【2010/08/03】 KMRCLを眺める(183) QUIT: g000001

【2010/08/04】 KMRCLを眺める(184) COMMAND-LINE-ARGUMENTS: g000001

【2010/08/05】 (45)TAO/ELIS上でのCommon Lispの実現(1986): g000001

【2010/08/06】 (46)TAO/ELIS上でのCプログラミング環境(1986): g000001

【2010/08/08】 KMRCLを眺める(185) COPY-FILE: g000001

【2010/08/09】 ELIS復活祭参加してきました!: g000001

【2010/08/10】 ELIS復活祭メモ(1) (!(member ...))の謎: g000001

【2010/08/11】 ELIS復活祭メモ(2) ELIS-8200: g000001

【2010/08/12】 ELIS復活祭メモ(3) TAOではマクロがFUNCALL/APPLYできる: g000001

【2010/08/13】 KMRCLを眺める(186) CWD: g000001

【2010/08/14】 Common Lispの変数の種類と振舞い: g000001

【2010/08/15】 ELIS復活祭メモ(4) TAO/ELISのメインエディタZENと開発環境: g000001

【2010/08/16】 KMRCLを眺める(187) CANONICALIZE-DIRECTORY-NAME: g000001

【2010/08/17】 KMRCLを眺める(188) PROBE-DIRECTORY: g000001

【2010/08/18】 KMRCLを眺める(189) PRETTY-DATE: g000001

【2010/08/19】 Planet Common Lisp 日本 超手抜き版 作ってみました: g000001

【2010/08/05】 Common Lisp HyperSpec を眺める (1) zerop - 刺身☆ブーメランのはてなダイアリー: a666666

【2010/08/20】 KMRCLを眺める(190) PRETTY-DATE-UT: g000001

【2010/08/21】 vimでREPL: sile

【2010/08/22】 Smiley Hackathon #9に参加してきました!: g000001

【2010/08/23】 KMRCLを眺める(191) DATE-STRING: g000001

【2010/08/24】 KMRCLを眺める(192) PRINT-FLOAT-UNITS: g000001

【2010/08/25】 本当にLispはカッコが多い? - 八発白中: nitro_idiot

【2010/08/26】 KMRCLを眺める(193) POSIX-TIME-TO-UTIME: g000001

【2010/08/26】 Common Lisp から MeCab を手抜きで使う方法(SBCL 限定): quek

【2010/08/26】 Common Lisp HyperSpec を眺める (3) write-to-string - 刺身☆ブーメランのはてなダイアリー: a666666

【2010/08/27】 KMRCLを眺める(194) UTIME-TO-POSIX-TIME: g000001

【2010/08/28】 REPLでTwitter: g000001

【2010/08/28】 Common Lisp で実装された全文検索エンジン Montezuma: quek

【2010/08/29】 KMRCLを眺める(195) MONTHNAME : g000001

【2010/08/30】 KMRCLを眺める(196) DAY-OF-WEEK : g000001

【2010/08/31】 KMRCLを眺める(197) FUNCTION-TO-STRING: g000001

【2010/09/01】 重なったフィルターをLISPで左から右に簡潔で読み易く書きたい: g000001

【2010/09/02】 KMRCLを眺める(198) GENERALIZED-EQUAL-FUNCTION: g000001

【2010/09/03】 Common LispでClojure風の無名関数を使う - 八発白中: nitro_idiot

【2010/09/04】 KMRCLを眺める(199) GENERALIZED-EQUAL-ARRAY: g000001

【2010/09/00】 Common Lisp HyperSpec を眺める (4) write-string - 刺身☆ブーメランのはてなダイアリー: kyanny

【2010/09/06】 KMRCLを眺める(200) GENERALIZED-EQUAL-HASH-TABLE : g000001

【2010/09/07】 KMRCLを眺める(201) CLASS-SLOT-NAMES : g000001

【2010/09/08】 LISP365 に投稿するリンクを作るブックマークレット (2) - 刺身☆ブーメランのはてなダイアリー: kyanny

【2010/09/08】 KMRCLを眺める(202) GENERALIZED-EQUAL-FIELDED-OBJECT : g000001

【2010/09/09】 KMRCLを眺める(203) STRUCTURE-SLOT-NAMES : g000001

【2010/09/09】 生まれて3日目のUn-Common Lisp - 八発白中: nitro_idiot

【2010/09/10】 KMRCLを眺める(204) GENERALIZED-EQUAL : g000001

【2010/09/11】 ZetalispのPKG-BIND : g000001

【2010/09/12】 このブログのKMRCLのエントリーをSLIMEから検索する : g000001

【2010/09/13】 このブログのKMRCLのエントリーをSLIMEから検索する(2) : g000001

【2010/09/14】 コンスセルのアスキーアート : g000001

【2010/09/15】 OKI ISLispがislisp.orgにて再公開! : g000001

【2010/09/15】 SBCLのリーダを上書きして"超リードマクロ"を実装 - 八発白中: nitro_idiot

【2010/09/16】 超リードマクロに対して超普通 : g000001

【2010/09/17】 ディスパッチ・マクロ文字の引数の思いがけない使い方を知りたい : g000001

【2010/09/18】 (47)“日本語上手”なCommon Lisp ~LispマシンExplorerでの実現~(1987) : g000001

【2010/09/19】 簡単なSWANKの拡張で適当補完 : g000001

【2010/09/19】 letter: mmap gray stream: quek

【2010/09/20】 KMRCLを眺める(205) SEED-RANDOM-GENERATOR : g000001

【2010/09/21】 数理システム Common Lisp セミナ 2010-09-21 : g000001

【2010/09/22】 UNF: Common Lisp版: sile

【2010/09/23】 スキップリスト: sile

【2010/09/23】 数理システム Common Lisp セミナ 2010-09-21 (2) : g000001

【2010/09/24】 Packrat Parsing: sile

【2010/09/25】 letter: 数理システム Common Lisp セミナー: quek

【2010/09/26】 HAMT(Hash Array Mapped Trie): sile

【2010/09/26】 構造体のスタックへの割り当て: sile

【2010/09/26】 KMRCLを眺める(206) RANDOM-CHOICE : g000001

【2010/09/26】 series を使ってみた: mori_dev

【2010/09/28】 [OnLisp]マクロでapply: mori_dev

【2010/09/28】 KMRCLを眺める(207) CMSG : g000001

【2010/09/29】 HAMT: 実装してみた感想等: sile

【2010/09/29】 SLIMEばつ牛ン (1) slime-eval-defun : g000001

【2010/09/30】 [OnLisp] get-setf-method のところは get-setf-expansion にすると動く: mori_dev

【2010/09/30】 クイックソートの内部ループ: sile

【2010/10/01】 [CL][PAIP] case 構文のキーを括弧でくくると何が変わるのか: mori_dev

【2010/10/01】 KMRCLを眺める(208) CMSG-C : g000001

【2010/10/02】 '(#'fun1 #'fun2 は誤用となることがある: mori_dev

【2010/10/02】 adefun を読む!: mori_dev

【2010/10/02】 マルチキークイックーソート: sile

【2010/10/03】 KMRCLを眺める(209) CMSG-ADD : g000001

【2010/10/04】 KMRCLを眺める(210) CMSG-REMOVE : g000001

【2010/10/05】 SLIMEばつ牛ン (2) slime-apropos : g000001

【2010/10/05】 letter: (series::install) して (declare (optimizable-series-function)) する: quek

【2010/10/06】 予想外の nil: mori_dev

【2010/10/06】 letter: Common Lisp でメール送信: quek

【2010/10/07】 KMRCLを眺める(211) FIXME : g000001

【2010/10/07】 letter: CLSQL で MySQL につなぐ: quek

【2010/10/08】 letter: cl-typesetting で日本語出力: quek

【2010/10/09】 Quicklisp素晴しい! : g000001

【2010/10/09】 [CL] *query-io* メモ: mori_dev

【2010/10/09】 letter: cl-twitter で OAuth: quek

【2010/10/10】 letter: Quicklisp のメモ: quek

【2010/10/10】 (48) Lisp のプログラミング環境 (<大特集>新しいプログラミング環境) : g000001

【2010/10/11】 letter: もう一つの Tilde for SBCL のやり方 (sb-int:encapsulate): quek

【2010/10/12】 letter: Series の collect-ignore: quek

【2010/10/12】 KMRCLを眺める(212) MAKE-PROCESS : g000001

【2010/10/13】 KMRCLを眺める(213) DESTROY-PROCESS : g000001

【2010/10/14】 DAWG2(1): ソート済みファイルからのトライ構築: sile

【2010/10/14】 KMRCLを眺める(214) MAKE-LOCK : g000001

【2010/10/15】 letter: ひきこもる: quek

【2010/10/15】 KMRCLを眺める(215) WITH-LOCK-HELD : g000001

【2010/10/16】 DAWG2(2): ソート済みファイルからのDAWG構築: sile

【2010/10/16】 EmacsのBackward Up Listの動きが気に入らない : g000001

【2010/10/17】 EmacsのBackward Up Listの動きが気に入らない(2) : g000001

【2010/10/18】 letter: 整数を表現するのに必要なビット数を求める: quek

【2010/10/18】 KMRCLを眺める(216) WITH-TIMEOUT : g000001

【2010/10/19】 letter: Common Lisp は動的型付け言語: quek

【2010/10/19】 KMRCLを眺める(217) PROCESS-SLEEP : g000001

【2010/10/20】 letter: float を 3 つの整数で表現する: quek

【2010/10/20】 KMRCLを眺める(218) CDATA-STRING : g000001

【2010/10/21】 llvm: ビットコードのデコード: sile

【2010/10/21】 KMRCLを眺める(219) FIND-START-TAG : g000001

【2010/10/21】 letter: Named-Readtables いいね: quek

【2010/10/22】 letter: | sbcl: quek

【2010/10/22】 KMRCLを眺める(220) FIND-END-TAG : g000001

【2010/10/23】 Perl6の>><<演算子を真似てみる : g000001

【2010/10/24】 erlterm: Erlang項とCommon Lispオブジェクトの相互変換: sile

【2010/10/25】 KMRCLを眺める(221) POSITIONS-XML-TAG-CONTENTS : g000001

【2010/10/26】 Shibuya.lisp Hackathon #1開催 : g000001

【2010/10/27】 リーダーマクロ使わないで"[]"を"()"として利用できるか : g000001

【2010/10/28】 KMRCLを眺める(222) XML-TAG-CONTENTS : g000001

【2010/10/29】 APROGNの実装色々 : g000001

【2010/10/30】 letter: 第5回ありえるえりあ勉強会 〜「Lisp脳」勉強会 〜: quek

【2010/10/30】 letter: (declaim (declaration あび)): quek

【2010/10/31】 この先一年の年間ドッグフーディング : g000001

【2010/11/01】 Seriesの関数名が長い : g000001

【2010/11/01】 DAWG2(3): cl-dawg: sile

【2010/11/01】 Common Lispでスクリプトを書こう - 八発白中: nitro_idiot

【2010/11/02】 Seriesを引数に取ってSeriesを返す関数 : g000001

【2010/11/03】 *SERIES-IMPLICIT-MAP*の怪 : g000001

【2010/11/04】 letter: Stumpwm で It's All Text!: quek

【2010/11/04】 CL数学処理ライブラリ nurarihyon 01: garaemon

【2010/11/05】 letS*への道 : g000001

【2010/11/06】 KMRCLを眺める(223) CDATA-STRING : g000001

【2010/11/07】 Seriesでリーダーマクロ : g000001

【2010/11/08】 READのrecursive-pの働き (1) : g000001

【2010/11/09】 KMRCLを眺める(224) WRITE-CDATA : g000001

【2010/11/10】 KMRCLを眺める(225) XML-DECLARATION-STREAM : g000001

【2010/11/11】 KMRCLを眺める(226) DOCTYPE-FORMAT : g000001

【2010/11/12】 Medleyを使ってみよう(1) : g000001

【2010/11/13】 同じ年月は同じグループとしてカウントして数を求める例でのコード比較を Common Lisp でも : g000001

【2010/11/14】 COMPILER-LETの使い道 : g000001

【2010/11/15】 KMRCLを眺める(227) DOCTYPE-STREAM : g000001

【2010/11/16】 car/cdrの別表記を考えてみた : g000001

【2010/11/17】 B木: sile

【2010/11/17】 letter: CLSQL で MySQL の auto_increment と text を使う: quek

【2010/11/18】 2日間まるごとLISPセミナー 2010 1日目 : g000001

【2010/11/19】 2日間まるごとLISPセミナー 2010 2日目 : g000001

【2010/11/20】 LAMBDAを使うなスタイル (1) : g000001

【2010/11/21】 アナフォリックマクロのITをどうするか : g000001

【2010/11/22】 KMRCLを眺める(228) SGML-HEADER-STREAM : g000001

【2010/11/23】 CL数学処理ライブラリ nurarihyon 02: garaemon

【2010/11/24】 Land of Lisp 読書記録 (1) : g000001

【2010/11/25】 GOOでL-99 (P23 指定した個数の要素をランダムに選択) : g000001

【2010/11/26】 KMRCLを眺める(229) SCORE-MULTIWORD-MATCH : g000001

【2010/11/27】 Shibuya.lisp TT#6が開催されました! : g000001

【2010/11/28】 XCLがSBCLより速いところ : g000001

【2010/11/29】 文字列の繰り返し : g000001

【2010/11/30】 Lemmensさんメモ : g000001

【2010/11/30】 letter: Common Lisp から OAuth で Twitter: quek

【2010/12/01】 prognを活用しよう(Emacs Advent Calendar jp:2010) : g000001

【2010/12/01】 letter: Common Lisp で Twitter の User Streams: quek

【2010/12/02】 ClozureCLのdirectory関数でディレクトリ一覧を取得する方法: sile

【2010/12/03】 letter: SLIME の repl でアイコンを表示できるようになった: quek

【2010/12/03】 LISP365も残すところあと10日!! : g000001

【2010/12/04】 KMRCLを眺める(230) MULTIWORD-MATCH : g000001

【2010/12/05】 Land of Lisp 読書記録 (2) : g000001

【2010/12/06】 部分適用のリーダーマクロ : g000001

【2010/12/07】 letter: SERIES の producing: quek

【2010/12/07】 READ系関数のEOF-ERROR-Pを活用できないか : g000001

【2010/12/08】 letter: SERIES で scan-file 系を実装するとき: quek

【2010/12/08】 LAMBDA代替記法全部のせ : g000001

【2010/12/09】 C.I.CLを眺める(1) ENSURE-LIST : g000001

【2010/12/10】 letter: Climacs で T-Code: quek

【2010/12/10】 メタプログラミングRuby的CLOS (1) : g000001

【2010/12/11】 メタプログラミングRuby的CLOS (2) : g000001

【2010/12/12】 Common Lispで日常のテキスト処理 : g000001

Common Lispで日常のテキスト処理

| 19:05 | Common Lispで日常のテキスト処理 - わだばLisperになる を含むブックマーク はてなブックマーク - Common Lispで日常のテキスト処理 - わだばLisperになる

いよいよ今日はLISP365の最終日です。

LISP365のHTMLから参加者のエントリーの情報を抜き出して加工し、次のまとめエントリーにしようと考えているのですが、ついでなので、そういう自分の日常作業手順を書いてみようかなと思います。

データを取得

HTTPクライアントでスクレイピング、という感じが多いと思うのですが、今回は、エントリーの必要な部分だけファイルにコピペで抜き出しました。

コメントのHTMLにミスがあったりするため少し手作業で修正。問題の発見方法については、次のHTMLをS式に変換の関数で発見できるので、それで場所を特定して修正しました。

HTMLをS式に変換

作成したHTMLの断片が纒まったファイルは、

<div>
 ...
</div>

が連鎖しているという内容なので、ひとつずつ読んでは、S式で出力するものを作成します

(defun read-xml-elt (&optional (s *standard-input*) (eof-error-p T) eof-value)
  (declare (ignore eof-error-p))
  (if (eq eof-value (peek-char t s nil eof-value))
      eof-value
      (or (xmls:parse s)
          eof-value)))

こんな感じで作ってみました。READ-LINEのXML版みたいなそうでもないようなものです。

パーズには、CLiki: xmlsを使います。XMLS:PARSEがEOFに遭遇するとNILを返すのですが、SCAN-STREAMで使うには都合が悪いのでEOF-VALUEを引数として受けとるようにしています。

組み立てられるS式は、エントリーごとに

("div" (("class" "comment_entry"))
  ("h4" NIL
   ("img"
    (("width" "18")
     ("src"
      "http://a3.twimg.com/profile_images/849769127/g000001-48x48_normal.jpg")
     ("height" "18") ("alt" "G000001-48x48_normal")))
   ("a" (("href" "/users/2658")) "g000001") "-"
   ("span" (("class" "comment_date")) "(2010/12/11 22:48)"))
  ("p" NIL "【2010/12/11】"
   ("a" (("href" "http://cadr.g.hatena.ne.jp/g000001/20101211/1292071752"))
    "メタプログラミングRuby的CLOS (2) - わだばLisperになる - cadr group")
   ("br" NIL) "いよいよ明日で最後か!"))

という感じです。

(タグ 内容)もしくは、((タグ 属性) 内容)

という形式が多いと思いますが、XMLSは、

(タグ ((属性名 値) ...) 内容)

という形式のようです。

S式から必要な情報を抜き出し

XPATHなどあると思うのですが、今回の場合、使い方を調べるより作った方が早いので、適当なものを作ります。

(defun find-elt (path data)
  (if (null path)
      data
      (let ((data (find (car path) data
                        :test (lambda (x y) (and (stringp y) (string= x y)))
                        :key #'zl:car-safe)))
        (find-elt (cdr path) data))))

(defun attribute (name elt)
  (let ((alist (second elt)))
    (second (assoc name alist :test #'string=))))

(defun content (elt)
  (third elt))

みてのとおり同じ階層に同じキーが並んでいても最初のものだけしか読みません。良いんです。良いんです。

(content (find-elt '("p" "a") エントリー))
;=> "メタプログラミングRuby的CLOS (2) - わだばLisperになる - cadr group"

こんな感じで抜き出すことができます。

S式から文字列を作成

(defun elt-to-entry (elt count-tab out)
  (let* ((date (content (find-elt '("p") elt)))
         (url (attribute "href" (find-elt '("p" "a") elt)))
         (title (content (find-elt '("p" "a") elt)))
         (name (content (find-elt '("h4" "a") elt)))
         (count (incf (gethash name count-tab 0)))
         (hatena-p (ppcre:create-scanner "hatena.ne.jp")))
    (format out
            "~A ~A: ~A<br />"
            (normalize-date date)
            (if (and (ppcre:scan hatena-p url) (< 1 count))
                title
                (write-xml-to-string `("a" (("href" ,url)) ,title)))
            name)))

のようにしてエントリーのS式を文字列に変換します。

いろいろ調整しているところ

  • WRITE-XML-TO-STRING

XMLSのWRITE-XMLが文字列を出力するようにしたものです。書き方によっては、いらなかったかもしれません。

(defun write-xml-to-string (xml)
  (with-output-to-string (out)
    (xmls:write-xml xml out)))
  • NORMALIZE-DATE

【2010/1/1】だったり、【2010/01/01】だったりするものを【2010/01/01】に正規化するものです。

日常作業では割と多い気がしますが、もっと汎用的に作っておいてライブラリに入れておくのも良いかなと思いました。

(defun normalize-date (string)
  (ppcre:register-groups-bind ((#'parse-integer yyyy)
                               (#'parse-integer dd)
                               (#'parse-integer mm))
                              ("【(\\d+)/(\\d+)/(\\d+).*】" string)
    (format nil "【~D/~2,'0D/~2,'0D】" yyyy dd mm)))
  • HATENA-P

はてな日記は、はてな日記のURLがエントリー中にあるとそのエントリーにトラックバックを飛します。

今回、トラックバックが何十と飛んでしまうのを防止するため、最初の一回目だけ飛すようにしているところです。

hatena-p (ppcre:create-scanner "hatena.ne.jp")
...

(if (and (ppcre:scan hatena-p url) (< 1 count))
    title
    (write-xml-to-string `("a" (("href" ,url)) ,title)))
  • 集計

ハッシュテーブルを使ってエントリー数を集計し、それをALISTに変換し、ソートして出力します。

  • 実行させる部分

RUNというまとめ関数を作成して入出力をまとめます。

使っているライブラリは、Series、Alexandria、f-underscoreです。

WITH-<、WITH->は、WITH-OPEN-FILEと書くのが面倒なので簡単に書けるようにしたものです。

(defun run ()
  (let ((count-tab (make-hash-table :test #'equal)))
    (with-< (in "/tmp/memo-2010-12-12.txt")
      (with-> (out "/tmp/foo.html")
        (collect-stream out
                        (scan-stream in #'read-xml-elt)
                        (f (elt out)
                          (elt-to-entry elt count-tab out)))
        ;; 集計
        (iterate (((name cnt)
                   (scan-alist (sort (alexandria:hash-table-alist count-tab)
                                     #'>
                                     :key #'cdr))))
          (format out "~A: ~D回<br />" name cnt))))))

最近は、このRUNのようにとりあえず関数にまとめて、slime-interactive-evalで(run)を実行するのが気に入っています。

メリットとしては、バッファやカーソルの位置に関わらず実行できるところでしょうか。

HTMLを加工して文字列にしたり、再度HTMLを組み立てたりは、実行結果をみつつ作業することが多い気がします。

自分は、こういう時にはLISPの対話環境は割と便利だなと思っています。

LISPは敷居が高い、日常的な作業に使えない、と思っている方は、まずは、こういう処理で遊んでみるのも良いのではないでしょうか。

*1:グループ日記からはてな日記へのリンクはトラックバックが飛びすぎるので最初の1件だけリンクにしてあります

2010-12-11

メタプログラミングRuby的CLOS (2)

| 21:49 | メタプログラミングRuby的CLOS (2) - わだばLisperになる を含むブックマーク はてなブックマーク - メタプログラミングRuby的CLOS (2) - わだばLisperになる

メタプログラミングRubyで見掛けたものを考えることの2回目

同じコードを何度も書くのが面倒臭いですしおすし

こういう場合は、CLの場合、クラスは関係なしで、そのものずばりマクロかなと思いました。

(macrolet ((define-component (name)
             `(let ((info ...)
                   (price ...))
                (def ...))))
  (define-component mouse)
  (define-component cpu)
  (define-component keyword))

のような。

もっとクラスの情報をクラス定義自体から引き出して動的に生成したい、ということになると構文上での操作ではなく、クラスオブジェクトの操作になってくるんだと思いますが、構文上の操作だけなら、やっぱりマクロが簡単だと思います。

3回目につづく

2010-12-10

メタプログラミングRuby的CLOS (1)

| 19:43 | メタプログラミングRuby的CLOS (1) - わだばLisperになる を含むブックマーク はてなブックマーク - メタプログラミングRuby的CLOS (1) - わだばLisperになる

巷では、メタプログラミングRubyの評判が高い様子ですが、Common LispもCLOSという動的なオブジェクト指向システムを持っているぞ、ということでこの本で取り上げられている手法にちまちま対抗意識を燃やしてチャレンジしてみることにしました。

といっても全部やるのも大変なので目についたところを適当に再現して遊んでみます。

まず、RubyとCLOSで違うのは、CLOSはクラスの中でメソッドが定義されているわけではない、というところ。

この辺りのギャップが結構あります。

それはさておき、適当に真似てみます。

下準備

(defclass my-class () ())

;; make-instanceが長いので、newという別名を付けてみる
(setf (fdefinition 'new)
      (symbol-function 'make-instance))

(defvar *c* (new 'my-class))

メソッドを動的に呼ぶ

とりあえず普通の書き方
(defmethod my-method ((self my-class) arg)
  (* 2 arg))

(my-method *c* 8)
;=> 16
動的と思われる書き方
(let ((meth #'my-method))
  (funcall meth
           *c*
           8))
;=> 16

メソッドがファーストクラスなので変数に入れて呼べます。

メソッド名を文字列等から作成
;; MY-METHODという名前のシンボルを文字列から作成して呼び出し
(funcall (intern (concatenate 'string "MY" "-" "METHOD"))
         *c*
         8)
;=> 16

メソッドを動的に作る

作る方ですが、お手軽に行くならEVAL、他にはメソッドオブジェクトを色々直接操作という感じになると思います

定義する式を作成してEVAL
(let ((name (intern (concatenate 'string "MY" "-" "METHOD"))))
  (eval
   `(defmethod ,name ((self my-class) arg)
      (* 3 arg))))

(my-method *c* 3)
;=> 9
まるごと無名でも行けるぜ、ヒャッハーみたいな
(let* ((gf (new 'standard-generic-function))
       (meth (new 'standard-method
                  :function (lambda (args ignore)
                              (destructuring-bind (self arg)
                                                  args
                                (* arg 3)))
                  :lambda-list '(self arg)
                  :specializers (list (find-class 'my-class)
                                      (find-class t)))))
  (add-method gf meth)
  (funcall gf *c* 3))
;=> 9

まあ、長いですけども…

次回につづく

2010-12-09

C.I.CLを眺める(1) ENSURE-LIST

| 22:34 | C.I.CLを眺める(1) ENSURE-LIST - わだばLisperになる を含むブックマーク はてなブックマーク - C.I.CLを眺める(1) ENSURE-LIST - わだばLisperになる

KMRCLも230回に及び、残りは、1ファイル完結で長かったり、理解が難しかったりするので、KMRCL以外もちょこちょこ眺めて行こうかなと思います。

どのユーティリティにしようかなと思いましたが、以前からなんとなく気になっていたPascal J. Bourguignon氏のライブラリを眺めることに。

Bourguignon氏は、comp.lang.lisp等で質問に答えたりしていて良く目にするのですが、その際に自作のユーティリティを示すことが結構あり、しかも、それが面白いので気になっていました。

ユーティリティは、

からgitで取得できます。ちょっと導入に癖がありますが、ページの案内どおりにしていれば導入できるでしょう。

ところで、com.informatimago.common-lispだと非常に長いので、どういう風に略そうかと悩みましたが、PJBCLとか勝手な名前を付けるのもあれだし、comp.lang.lispをc.l.lと略すようにC.I.CLと略してみることにしました。

今回は、そのC.I.CLのlist.lispからENSURE-LISTです。

まず、list.lispファイル全体で、パッケージが切ってあって、:com.informatimago.common-lisp.listというパッケージになっています。

実装は、

(DEFUN ENSURE-LIST (ITEM)
  "
RETURN: item if it's a list or (list item) otherwise.
"
  (IF (LISTP ITEM) ITEM (LIST ITEM)))

となっています。

KMRCLだと、KMRCL:MKLISTで同じものが用意されています。

しかし、命名方としては、ENSURE-系の方が動作を的確に表現できているのではないかと。

そして、何故かコードが珍しく大文字です。

ドキュメント文字列の最初と最後の改行は何故なのか気になりますが、見易さへの配慮でしょうか。

コーディングスタイル的に色々と謎なこだわりが多そうなのが眺めていて面白いです。

動作は

(use-package :com.informatimago.common-lisp.list)

(ensure-list 'a)
;=> (A)

(ensure-list '(a))
;=> (A)

(kmrcl:mklist 'a)
;=> (A)

というところ。

2010-12-08

LAMBDA代替記法全部のせ

| 23:44 | LAMBDA代替記法全部のせ - わだばLisperになる を含むブックマーク はてなブックマーク - LAMBDA代替記法全部のせ - わだばLisperになる

最近のLISP方言では、(lambda (x) (list x))が、[list _]と書けたり、#(list %)と書けたりしますが、便利だなと思いつつもlambdaのままで日々を過しております。

でも、ささッと書くには記法が簡単な方が便利なのは確かです。

代替記法は色々ありどれにしたら良いのか迷う程ですが、考えるのも面倒なので普段使うパッケージにとにかく全部入れていつでも使えるようにしてみることにしました。

ちょっと探してみただけでも、CLのライブラリには、

  • Arnesiの#L記法
  • cl-op
  • curly
  • f-underscore
  • metatilities

等があるようです。

;; 導入方法
;; ARNESI:ENABLE-SHARP-L-SYNTAX
(IT.BESE.ARNESI:ENABLE-SHARP-L-SYNTAX)

;; cl-op
;; http://code.google.com/p/cl-op/
(import 'cl-op:op)

;; curly
;; http://www.cliki.net/curly
(curly:enable-curly-syntax)

;; gauche
;; http://blog.practical-scheme.net/gauche/20100428-shorter-names
;; 自作しましょう

(import 'metatilities::\\)

;; f-underscore
(use-package :f-underscore)
;; 普通のLAMBDA
(mapcar (lambda (x) (parse-integer (string x)))
        '("1" "2" "3" "4"))

;; 関数合成な感じ
(mapcar (compose #'parse-integer #'string)
        '("1" "2" "3" "4"))

;; Arnesi L#
(mapcar #L(parse-integer (string !1))
        '("1" "2" "3" "4"))

;; f-underscore
(mapcar (f_ (parse-integer (string _)))
        '("1" "2" "3" "4"))

;; metatilities::\\
(mapcar (\\ x = parse-integer (string x))
        '("1" "2" "3" "4"))

;; Gauche
(mapcar (^x (parse-integer (string x)))
        '("1" "2" "3" "4"))

;; Arc
(mapcar (fn (x) (parse-integer (string x)))
        '("1" "2" "3" "4"))

;; curly
(mapcar {parse-integer string}
        '("1" "2" "3" "4"))

;; Gaucheの$
(mapcar ($ parse-integer $ string $)
        '("1" "2" "3" "4"))

ちょっと込み入ったもの

(mapcar (lambda (x) (parse-integer (string x) :radix 16))
        '(a b c d e))

;; f-underscore
(mapcar (f_ (parse-integer (string _) :radix 16))
        '(a b c d e))

;; metatilities::\\
(mapcar (\\ x = parse-integer (string x) :radix 16)
        '(a b c d e))
;=> (10 11 12 13 14)

とりあえず、比較して一覧に纒めるのも疲れる位、様々な試みがあることは分かりました。

なんとなく、常用するならf-underscoreに落ち着くような気はしています。

2010-12-07

READ系関数のEOF-ERROR-Pを活用できないか

| 23:15 | READ系関数のEOF-ERROR-Pを活用できないか - わだばLisperになる を含むブックマーク はてなブックマーク - READ系関数のEOF-ERROR-Pを活用できないか - わだばLisperになる

READ系関数のEOF-ERROR-PはデフォルトがTですが、普通使うときは、大抵NILにすることが多いと思います。

これのデフォルトがNILだったら、

(loop :for line := (read-line in nil) :while line :collect line)

ではなく、

(loop :for line := (read-line in) :while line :collect line)

のようにすっきり書けたりするのになと常々思っていますが、逆に、これを活用できないかということで、以前、積極的にEND-OF-FILEシグナルを拾いに行く試みをしたことがありました。

今日CLerのquekさんとの雑談の中で、もしかしたらループの中でEOFかどうかを比較するコストが低いかもしれず、結果として速いかもしれない、という話になり折角なので実験してみることにしました。

まずは、/usr/share/dict/wordsでの比較。98569行のファイルです。

;; EOFをつかまえる
(dotimes (i 100)
  (with-open-file (in "/usr/share/dict/words")
    (atap 0
      (handler-case (loop :for c := (read-char in) :do (incf it))
        (end-of-file () nil)))))
;⇒ NIL
----------
Evaluation took:
  7.640 seconds of real time
  7.620000 seconds of total run time (7.580000 user, 0.040000 system)
  99.74% CPU
  18,289,984,221 processor cycles
  1,200,560 bytes consed

Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz

;; atap
(atap 0 ...) ≡ (LET ((IT 0)) ... IT)
;; 通常
(dotimes (i 100)
  (with-open-file (in "/usr/share/dict/words")
    (loop :for c := (read-char in nil nil) :while c :count c)))
;⇒ NIL
----------
Evaluation took:
  7.996 seconds of real time
  7.990000 seconds of total run time (7.900000 user, 0.090000 system)
  99.92% CPU
  19,144,510,308 processor cycles
  1,102,048 bytes consed

Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz

何度か平均してみましたが、極わずかのほんのちょっとだけ速い気がします。

次に512MBのファイルの読み込みを試してみます

$ dd if=/dev/zero of=/tmp/test.img bs=1024 count=$((1024*512))
;; 通常 ループ内では、-1と比較
(with-open-file (in "/share/music/tmp/test.img" :element-type '(unsigned-byte 8))
  (loop :for b := (read-byte in nil -1) :until (= -1 b) :count b))
;⇒ 536870912
----------
Evaluation took:
  35.383 seconds of real time
  34.980000 seconds of total run time (34.690000 user, 0.290000 system)
  98.86% CPU
  84,706,093,341 processor cycles
  512,976 bytes consed

Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz
;; EOFを掴まえる
(with-open-file (in "/share/music/tmp/test.img" :element-type '(unsigned-byte 8))
  (atap 0
    (handler-case (loop :for c := (read-byte in) :do (incf it))
      (end-of-file () nil))))
;⇒ 536870912
----------
Evaluation took:
  34.367 seconds of real time
  33.790000 seconds of total run time (33.520000 user, 0.270000 system)
  98.32% CPU
  82,272,802,536 processor cycles
  506,608 bytes consed

Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz

これもほんのちょっ〜とだけ速い気がします。

おまけだと、IGNORE-ERRORSで捕捉しても速いことは速いです。スタイル的に微妙ですが…。

(with-open-file (in "/share/music/tmp/test.img" :element-type '(unsigned-byte 8))
  (ignore-errors (loop (read-byte in))))
;⇒ NIL
----------
Evaluation took:
  32.416 seconds of real time
  32.330000 seconds of total run time (32.040000 user, 0.290000 system)
  99.73% CPU
  77,605,457,589 processor cycles
  478,112 bytes consed

Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz

結論としては、微妙〜に速い気がする程度という感じになりましたが、探してみれば良い使いどころがあったりすることに期待したいです。逆に使ったら絶対駄目なところがあるのかもしれませんが。

おまけ HANDLER-CASEでEND-OF-FILEを掴まえるスタイルの欠点

HANDLER-CASEでEND-OF-FILEを掴まえるスタイルの欠点ですが、必ずエラーで抜けるため、フォームの返り値が使えないという欠点があります。

周りを値を収集するフォームで囲ってやらないと使い勝手が悪くなりますが、ここで、SeriesのGATHERERを使うと綺麗に書けます。

(with-open-file (in "/etc/passwd")
  (gatherlet ((g collect))
    (handler-case (loop (next-out g (read-line in)))
      (end-of-file () nil))
    (result-of g)))

;; gatherer
(with-open-file (in "/etc/passwd")
  (gathering ((g collect))
    (handler-case (loop (next-out g (read-line in)))
      (end-of-file () nil))))

まあ、Seriesには、SCAN-FILEがありますが。

2010-12-06

部分適用のリーダーマクロ

| 23:13 | 部分適用のリーダーマクロ - わだばLisperになる を含むブックマーク はてなブックマーク - 部分適用のリーダーマクロ - わだばLisperになる

ディスパッチマクロ文字の数引数が上手く使えたりするかも、と思い、

(set-dispatch-macro-character #\# #\[ #'|#[-reader|)
(set-syntax-from-char #\] #\) )

(defun |#[-reader| (s c n)
  (declare (ignore c))
  (let ((gs (collect (subseries (#Mgensym) 0 n))))
    `(lambda (,@gs) (,(read s T nil T)
                      ,@(read-delimited-list #\] s T)
                      ,@gs))))

のようなものを書いてみましたが、

(#[list] :foo)
;=> (:FOO)

(#0[list])
;=> NIL

(#2[list] 3 3)
;=> (3 3)

(#[string= :nil] :nil)
;=> T

(let* ((ss '("a" "abc" "abcdef"))
       (max (reduce #'max (cons "" ss) :key #'length)))
  (map nil (o #'prn #[rjust max]) ss))
;->      a
;      abc
;   abcdef
;
;=> NIL

;; ////
;; prn: Arcから
(defun prn (&rest args)
  (apply #'pr args)
  (terpri))

;; rjust Rubyから
(defun rjust (width string)
  (format nil "~V,@A" width string))

;; o: Cleanから
(setf (symbol-function 'o) #'kl:compose)

あまりぱっとしません。

Gaucheの$の方が便利な感じ

(let* ((ss '("a" "abc" "abcdef"))
       (max (apply #'max (mapcar #'length ss))))
  (map nil ($ prn $ rjust max $) ss))
;->      a
;      abc
;   abcdef
;
;=> NIL

以上、ありきたりな思い付きを垂れ流し。

2010-12-05

Land of Lisp 読書記録 (2)

| 22:50 | Land of Lisp 読書記録 (2) - わだばLisperになる を含むブックマーク はてなブックマーク - Land of Lisp 読書記録 (2) - わだばLisperになる

Land of Lispの読書記録 1章です。

GETTING STARTED WITH LISP

Lisp Dialects

現在、メジャーなLISP方言というと、ANSI Common Lisp (CLとも略される)とScheme。

この本では、ちょっとだけポピュラーな方ということで、CLを選択するとのこと。

日本だとSchemeになりそうですよね。

A Tale of Two Lisps

イラストであなた向けのLISP方言を3択で診断ということですが、3択診断はさておき、LISP方言の特徴の記述はそれなりに普通です。

Up-and-Coming Lisps

最近の流れということでClojureとArcの紹介

Lisp Dialects Used for Scripting

アプリケーションの組込みや、スクリプト向けの方言の紹介

Emacs Lisp、Guile(GNU)、Script-Fu(GIMP)

ANSI Common Lisp

CLのちょっとした歴史と、ANSIによる標準化、マルチパラダイム言語であることの紹介

Getting Started with CLISP

様々なOSに簡単に導入できるのでこの本ではCLISPを選択したとのこと

Installing CLISP

CLISPのインストールについて解説

Starting Up CLISP

clispを立ち上げて

[1]> (+ 3 (* 2 4))
11

とか(quit)

してみる

これでLISPでゲームを書く準備はOK

What You’ve Learned

1章のまとめ

あいかわらず謎のイラストと謎のギャグです。

2010-12-04

KMRCLを眺める(230) MULTIWORD-MATCH

| 22:34 | KMRCLを眺める(230) MULTIWORD-MATCH - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(230) MULTIWORD-MATCH - わだばLisperになる

今回はKMRCLのstrmatch.lispから、MULTIWORD-MATCHです。

ドキュメント文字列によると、区切り文字や単語の位置には無関係で、大文字小文字も区別しないで文字列に含まれる単語群が同一のものかを判定するようです。

動作は、

(kl:multiword-match "foo        bar   baz" "foo,bar,baz")
;=> T

(kl:multiword-match "***foo/bar/baz**" "FOO,BAZ,bar")
;=> T

(kl:multiword-match "***foo/bar/baz**" "FOO,BAZ,bbb")
;=> NIL

というところ

定義は、

(defun multiword-match (s1 s2)
  "Matches two multiword strings, ignores case, word position, punctuation"
  (let* ((word-list-1 (split-alphanumeric-string s1))
         (word-list-2 (split-alphanumeric-string s2))
         (n1 (length word-list-1))
         (n2 (length word-list-2)))
    (when (= n1 n2)
      ;; remove each word from word-list-2 as walk word-list-1
      (dolist (w word-list-1)
        (let ((p (position w word-list-2 :test #'string-equal)))
          (unless p
            (return-from multiword-match nil))
          (setf (nth p word-list-2) "")))
      t)))

となっています。

SPLIT-ALPHANUMERIC-STRINGが肝ですが、これはKMRCLのもので以前に取り上げています。

2010-12-03

LISP365も残すところあと10日!!

| 22:35 | LISP365も残すところあと10日!! - わだばLisperになる を含むブックマーク はてなブックマーク - LISP365も残すところあと10日!! - わだばLisperになる

昨年、発作的にRuby Advent Calendarが羨ましくなり、真似してCL Advent Calendarでもやってみようかと思いましたが、そこは一捻りした方が良いだろうということで、クリスマスまでじゃなくて、この先365日やってみよう!という、CL365というのを始めました。ちなみに365日というのに根拠はありません。

開始してすぐに、CL365じゃあまりにも限定的じゃないだろうか、誰も集まんないですしおすし!という意見を頂いたので、LISP365にしたんですが、結局Schemeと、Clojureのエントリーは合わせても10に満たない感じでした。

まあ、世の中そんなもんですよね。というか、まあ、私がCLerだからというのが最大の理由ですが。

そんな、LISP365ですが、2010/12/12で丸一年 365日が終了です!

まさに誰得なイベントでしたが、終わるとなるとちょっと寂しいですね(私が)。

良かったら、あと10日、記念エントリーを残してみてください。

今流行のAdvent Calendarと同じ体裁になっています。

2010-12-01

prognを活用しよう(Emacs Advent Calendar jp:2010)

| 11:21 | prognを活用しよう(Emacs Advent Calendar jp:2010) - わだばLisperになる を含むブックマーク はてなブックマーク - prognを活用しよう(Emacs Advent Calendar jp:2010) - わだばLisperになる

こんにちは、今年もEmacs Advent Calendarの季節です!

Emacsのちょっとした便利機能を紹介しようと思って色々考えたのですが、誰でも使えそうなtipsということで、今回は、.emacsを設定したい編集したりする際に便利に使えそうな progn の使い方を紹介したいと思います。

.emacsに色々設定を追加していくと、関連する項目をまとめたくなることがあります。

そういう時は、

;;; モードラインの時刻表示関係 ===================

;;  24時間表示にする
(setq display-time-24hr-format t)
(setq display-time-day-and-date t)
(display-time)

;;; 設定その101 ================================

という風に見出しを付けて編集しやすくしたりすると思うのですが、ここで、progn を使って関連の項目を一つの式にまとめると便利です。

prognでまとめると

(progn
  ;; モードラインの時刻表示関係 ==================

  ;;  24時間表示にする
  (setq display-time-24hr-format t)
  (setq display-time-day-and-date t)
  (display-time))

という風になります。

最大のメリットは、Emacsには、S式の編集支援機能が豊富にあるので、例えばC-M-kでまとめて切り取りが簡単にできるようになったりするところです。

この強力な編集機能が、散らかった.emacs整理に力を発揮するのです!

年末の.emacsの整理に progn いかがでしょうか。