Quicklisp導入

一部で話題のQuicklispを(会社のPCで)試したのでメモメモ。

QuicklispはASDF-INSTALLみたいに、指定したライブラリ+依存するライブラリをWEBから拾ってきてインストールしてくれるツールのようです。配布されているインストーラつぽいモノは 単一の .LISPファイルになっていて、依存ライブラリなし。
自分がヘボいのかなんだか分からないけど、ASDF-INSTALLがWindows環境で上手く動かないので代替手段として。今後の主力として期待。

インストールはhttp://cadr.g.hatena.ne.jp/g000001/20101009/1286607760を参考にしました。

$ wget http://beta.quicklisp.org/quicklisp.lisp
$ sbcl

単一ファイルなのでwgetで拾ってくるだけ。簡単ですね。

CL-USER> (load (merge-pathnames "quicklisp.lisp" (user-homedir-pathname)))
CL-USER> (quicklisp-quickstart:install)
CL-USER> (ql:add-to-init-file)

これでインストール完了。installの際に、proxy を指定するときは :proxy に "http://hogehoge:port"という形式で指定。デフォルトのインストール先("~/quicklisp/")が嫌なら :path にディレクトリを指定。
add-to-init-file は処理系の初期化ファイルに quicklispを loadするコードを追加します。具体的にはこんなコード。

;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
                                       (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))

間違いがある可能性が高いメモ

関数 引数 備考
ql:quickload "ライブラリ名" 引数で指定したライブラリ、および依存ライブラリをインストール
ql:system-apropos "ライブラリ名の部分" 引数で指定した文字列を含むライブラリを探し出す
ql:update-all-dists - インストール済みライブラリを全部最新化
ql:update-client - Quicklisp自体を更新
ql:add-to-init-file - 処理系の初期化ファイルにQuicklispの読み込み処理を書き込む

Re: case 構文のキーを括弧でくくると何が変わるのか

http://d.hatena.ne.jp/kitokitoki/20101001/p1

Common Lispは実装がいっぱいあるので、SBCLだけで考えると問題がある気がする。と思って他の処理系で実験。WindowsでのABCLとClozure Common Lisp

;; ABCL 0.18.0
(defvar letter 'u)
;; => LETTER

(case letter
  (s 's)
  (t 't)
  (u 'u)
  (otherwise 'nothing))
;; => T

(case letter
  ((s) 's)
  ((t) 't)
  ((u) 'u)
  (otherwise 'nothing))
;; => U
;; Welcome to Clozure Common Lisp Version 1.4-r13122  (WindowsX8632)!
(defvar letter 'u)
;; => LETTER

(case letter
  (s 's)
  (t 't)
  (u 'u)
  (otherwise 'nothing))
; Warning: T or OTHERWISE clause in the middle of a CASE statement.  Subsequent clauses ignored.
; While executing: CCL::CASE-AUX, in process listener(1).
;; => T

(case letter
  ((s) 's)
  ((t) 't)
  ((u) 'u)
  (otherwise 'nothing))
;; => U

ABCLは PAIPの説明通りの動き、CCLは括弧で括らないと警告された上でPAIPの説明通りの動きでした。
よく分からないけど「処理系依存を避けるなら、やっぱり括弧で囲んだほうがいい」と思ったのでした。

Shibuya.lisp Hackathon #1に行きたい

Shibuya.lisp Hackathon #1 : ATND が、人が集まってきたので現実味を帯び始めた今日この頃。
出来れば行きたい。

だがしかし、ハッカソンに参加したことのないボクはハッカソンが何なのかもよく分かっていない!ググッてみたところ

ハッカソンHackathon:Hack-a-thon)とは、とある開発テーマの技術に興味のあるプログラマーたちが、会議室やソファーがある場所などにノートPC持参で集まり、みんなで一緒にソフトウェアをハックしまくって楽しみ、最後に開発したアプリケーションやサービスを参加者全員の前でプレゼンするという、いわばギークのためのお祭りイベントです。

http://www.masahiko.info/it/archives/000958.html

とのこと。

ボクが全然ギークじゃないことは置いといて、テーマは当日適当に出して、適当に分かれるものなのでしょうか。「LISPなら何でもいい」とかなら、Windows7(64bit)でのお手軽快適Common Lisp環境作成か、Windows7(64bit)+CCL上でライブラリを動かしてみて動かん物を修正とか、ASDF-INSTALLに代わるモノの作成とかしてみたい。結構、参加表明している人はいるから、その人たちの「何をやりたい」も聞いてみたい。

CLSQL+SQLite3

Weblocksの裏側で動くDBアクセス周りはElephant、CLSQL、CL-PREVALENCEなど好きなものを使うことが出来ます。

今まで自宅ではPREVALENCEを使っていたのですが、ちょっとCLSQLに変えようかなと思い立ってソースを弄った結果動かない!何かが悪いらしいけど、何が悪いのか切り分けられませんでした。無念、後で調べるリスト入り。おWeblocks、未だに処理の流れが分からなくて、エラーになったときに解析できない・・・

で気分転換にCLSQLそのモノをちゃんと使えるようになろうと思ったのでした。今回はCLSQLのお話。ちなみにWindows XP、CCLで動かしています。

CLSQLはCommon Lispから各種DBに接続してゴニョゴニョ出来るライブラリです。今回、DBはSQLite3を使うのでCLSQL-SQLITE3を読み込みました。

CL-USER> (asdf:oos 'asdf:load-op :clsql-sqlite3)

clsql/uffi/ 内に libsqlite3.dllか sqlite3.dllが無いとエラーになります。この配置先パスは CLSQL-SYS:*FOREIGN-LIBRARY-SEARCH-PATHS* にパスを突っ込んでおけば、このリストの頭から順番に見ていくので、好きな場所に配置しても大丈夫。よかったですね。

CL-USER> (defpackage :jiro
           (:use :clsql :cl))
CL-USER> (in-package :jiro)

JIRO> (connect '("d:/data.db") :database-type :sqlite3)

適当にパッケージ作って遊んでます。
connectでDBと接続。第1引数の '("d:/data.db") はデータを保存するファイルのパス。データを残す必要はないけど、RDB的にデータを扱いたい場合は'(":memory:")を渡しておくとメモリ上にデータを置くだけっぽいです。

JIRO> (def-view-class book ()
        ((id :accessor id
             :initarg :id
             :type integer
             :db-constraints :not-null
             :db-kind :key)
         (name :accessor name
               :initarg :name
               :type (string 64))
         (authors :accessor authors
                  :db-kind :join
                  :db-info (:join-class author
                                        :home-key id
                                        :foreign-key book-id
                                        :set t))))
JIRO> (def-view-class author ()
        ((id :accessor id
             :initarg :id
             :type integer
             :db-kind :key
             :db-constraints :not-null)
         (name :accessor name
               :initarg :name
               :type (string 100))
         (book-id :accessor book-id
                  :initarg :book-id
                  :type integer)
         (books :accessor books
                :db-kind :join
                :db-info (:join-class book
                                      :home-key book-id
                                      :foreign-key id
                                      :set nil))))
JIRO> (create-view-from-class 'author)
JIRO> (create-view-from-class 'book)

def-view-classマクロはテーブルに対応するクラスを定義するらしい。通常のCLOSのクラス定義+少々という感じですね。:db-kind に:key を渡せば主キー、:join を渡せば実際のカラムではなく表結合した結果を保持するSLOTになります。:join-class の :set にnilを渡すと単一のオブジェクト、非nilを渡すとLISTが格納されるので、1:nの関係が表現出来ます。
create-view-from-class で実際にテーブルを作成します。drop-view-from-class でテーブルの削除も可能。ちなみにテーブル名はクラス名と同じ。

JIRO> (with-transaction ()
        (update-records-from-instance
         (make-instance 'book :id 1 :name "BOOK_0001"))
        (update-records-from-instance
         (make-instance 'author :id 1 :name "AUTHOR_0001" :book-id 1))
        (update-records-from-instance
         (make-instance 'author :id 2 :name "AUTHOR_0002" :book-id 1))
        (update-records-from-instance
         (make-instance 'book :id 2 :name "BOOK_0002"))
        (update-records-from-instance
         (make-instance 'author :id 3 :name "AUTHOR_0003" :book-id 2))
        (update-records-from-instance
         (make-instance 'author :id 4 :name "AUTHOR_0004" :book-id 2))
        (update-records-from-instance
         (make-instance 'author :id 5 :name "AUTHOR_0005" :book-id 2))
        (update-records-from-instance
         (make-instance 'author :id 6 :name "AUTHOR_0006" :book-id 2))
        (update-records-from-instance
         (make-instance 'author :id 7 :name "AUTHOR_0007" :book-id 2))
	)

この辺りで大雑把にレコードをインサートしています。本を2冊、1冊目には作者が二人、2冊目には作者が五人。

JIRO> (locally-enable-sql-reader-syntax)
JIRO> (let ((books (select 'book :where [and [>= [slot-value 'book 'id] 1]
                                             [<= [slot-value 'book 'id] 2]])))
        (flet ((view (lst &aux (book (car lst)))
                 (format t ">>> BOOK ~A : (id ~S) (name ~S) (authors " book (id book) (name book))
                 (dolist (author (authors book))
                   (format t "((id ~S) (name ~S))" (id author) (name author)))
                 (format t ")~%")))
          (mapc #'view books)))

locally-enable-sql-reader-syntaxは Queryを書く際にちょっと便利になるリーダーマクロを定義してくれているようです。select関数の :where に与えている [and 〜]の部分。ちなみにBOOKには2レコードしか入れていないので :whereに値を与えない場合と結果は同じはず。もっといっぱいレコードを追加して、条件式を適当に弄って遊べばいいと思うよ。

いっぱい書いたけど、よく分かってません。JOIN指定したモノは必ずJOINされて取れちゃうの?SQLレベルで一緒に取ってきてるの?それとも「BOOKを取得->BOOK_IDが取得したBOOKのIDと一致するAUTHORを取得」って感じでSQL乱発される?次はちゃんとマニュアル眺めながらお勉強します。

CLSQL - Common Lisp 用マルチプラットフォーム SQL インターフェース - Lispy Daysを参考にしました。

継続って何ナノさ

前回のABCLをビルドしてたらい回しさせてから早10日。その間、全然Common Lispを触っていません!Emacs Lispはちょっと触ったよ。

いきなり話が変わって、Common LispのWebアプリケーションフレームワーク `Weblocks'はAjaxと`継続'を使っているそうで。そしてボクは、未だに継続が理解出来ていない。

プログラミングにおいて継続(けいぞく、continuation、コンティニュエーション)とは、ある計算過程のある瞬間における、その過程の未来全体(デフォルト)を表すもの、あるいは計算過程の実行スナップショットと説明される。

継続 - Wikipedia

正直、この説明じゃ全然分からない。on lispでも継続の話は出ていたけど、イメージがつかない。「動き」「利点」「使いどころ」が自分の中で形にならない。なので、まずは継続から復習してみる。

Weblocksの再開は、もうちょっと後じゃよ。

ABCL 0.21.0

子供が産まれて自分の時間がほぼ無くなったワタクシ。ちょっと時間が出来たので先日リリースされた ABCL 0.21をビルドしてみました。

  1. ABCL 0.21のソースを取得
  2. JDK 6と antをインストール
  3. ABCL 0.21を展開
  4. 展開したディレクトリに入って "ant"
  5. ビルドが終わったら abcl

簡単ですね。お手軽Common Lisp

CLSQLのマニュアルを読む

CLSQLはCommon LispSQLなライブラリらしいです。現在マニュアルを読んでいます。自宅に帰ると赤さんのお世話があってサンプルを動かす暇がありません。ちくしょー。

あ、6月25日に父親になりました。よかったですね。