lispのpackageの仕組み(clisp)
そろそろ、毎度似たような関数を作っていることに気付いてきたので、共通化の仕組みを調べました。
http://www.geocities.jp/m_hiroi/xyzzy_lisp/abclisp17.htmlを参考にした。
上のサイトは、xyzzyでの説明で、下で動かしているのはclispです。
手探りでパッケージを弄ってみる。
初めの1歩
まず、数値の2乗を求める関数を使って実験をしました。
mathという名前を付けるのも恥ずかしかったので、まずは算数モジュールを作成
- sansu.cl
(defpackage "sansu") (in-package "sansu") (defun sqr (x) (* x x))
$ clisp [1]> (load "sansu.cl") ;; Loading file sansu.cl ... ;; Loaded file sansu.cl T [2]> (sansu::sqr 2) *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM> #<IO TERMINAL-STREAM>>: there is no package with name "SANSU" The following restarts are available: ABORT :R1 ABORT
いきなりかよ。
調査のため、パッケージリストを見るために、list-all-packagesを実行してみました。
Break 1 [3]> (list-all-packages) (#<PACKAGE GSTREAM> #<PACKAGE GRAY> #<PACKAGE I18N> #<PACKAGE SOCKET> #<PACKAGE FFI> #<PACKAGE SCREEN> #<PACKAGE CUSTOM> #<PACKAGE EXT> #<PACKAGE CLOS> #<PACKAGE CS-COMMON-LISP-USER> #<PACKAGE CS-COMMON-LISP> #<PACKAGE CHARSET> #<PACKAGE KEYWORD> #<PACKAGE SYSTEM> #<PACKAGE COMMON-LISP-USER> #<PACKAGE COMMON-LISP> #<PACKAGE EXPORTING> #<PACKAGE POSIX> #<PACKAGE REGEXP> #<PACKAGE READLINE> #<PACKAGE |sansu|>) Break 1 [3]>
#<PACKAGE |sansu|>ってのは定義の仕方がxyzzyとclispで違うのかもと思い、替えてみた。
defpackage、in-packageの引数を”で囲まないように修正しました。
- sansu.cl
(defpackage sansu) (in-package sansu) (defun sqr (x) (* x x))
再挑戦
Break 1 [3]> (load "sansu.cl") ;; Loading file sansu.cl ... ;; Loaded file sansu.cl T Break 1 [3]> (list-all-packages) (#<PACKAGE GSTREAM> #<PACKAGE GRAY> #<PACKAGE I18N> #<PACKAGE SOCKET> #<PACKAGE FFI> #<PACKAGE SCREEN> #<PACKAGE CUSTOM> #<PACKAGE EXT> #<PACKAGE CLOS> #<PACKAGE CS-COMMON-LISP-USER> #<PACKAGE CS-COMMON-LISP> #<PACKAGE CHARSET> #<PACKAGE KEYWORD> #<PACKAGE SYSTEM> #<PACKAGE COMMON-LISP-USER> #<PACKAGE COMMON-LISP> #<PACKAGE EXPORTING> #<PACKAGE POSIX> #<PACKAGE REGEXP> #<PACKAGE READLINE> #<PACKAGE |sansu|> #<PACKAGE SANSU>) Break 1 [3]> (sansu::sqr 2) 4 Break 1 [3]>
#<PACKAGE SANSU>というのが追加されて実行できるようになった。いいみたい。(いい加減ですが)
import と export
パッケージ指定せずに使えるようにしてみる。
使われる側でexportしました。
- sansu.cl
(defpackage sansu) (in-package sansu) (export '(sqr)) (defun sqr (x) (* x x))
使う側でimportしました。
Break 3 [5]> (import '(sansu::sqr)) T Break 3 [5]> (sqr 4) 16
使えました。
複数の関数や変数を一気にimportするには use-package するようです。
Break 1 [3]> (use-package "SANSU") T Break 1 [3]> (sqr 4) 16 Break 1 [3]>
ここで嵌ったのは、sansu ではなくて SANSU(大文字)にしないとエラーが発生したこと。
パッケージの定義を小文字でしているので、大文字でないといけないというのは、使いにくいと思いました。
追記(2008/08/02)
今ごろ追記ですみません。ブックマークしていただいたりしているので、佐野さんにコメントでアドバイス頂いた内容をエントリ本文にも反映します。(use-package “SANSU”) は、(use-package :sansu)の方が汎用的なので、:sansuというシンボル表記の方がいいです。
ここまでで自分ライブラリを作成することはできそうです。細かいことは追い追いで。
最近のclispなら「-modern」オプションで動かすといい感じになります。
Common Lispはcase-insensitiveなので、シンボルとかはread時に大文字にしちゃうんですよね。
NANRIさん、コメントありがとうございます!
教えていただいた方法で、いい感じになれました。
整理して次エントリに書こうと思います。
modernオプションはclispやaclなら良いんですけど
どの処理系でもというオプションではないので
(use-package :sansu)
という記法に修正する方がお勧めですね
佐野さん、コメントありがとうございます。反応おそくなりすみません。
そうなんですね!(use-package :sansu) という表記で一括インポートできました。
汎用的な書き方の方がいいので、この方法を使っていきます。