before lisps just part of the past #3 ~ irritating packages ~

15

Click here to load reader

Upload: samugari

Post on 11-May-2015

109 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

BeforeLISPs

Just Part of the Past

〜 #3 irritating Packages 〜

Page 2: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

PackageとSymbol● PackageはSymbolの集合

● 関数の集合だとか変数の集合という考え方はしない。ひたすらSymbolの集合。

● Symbolはいろいろな物を持っていて、関数として使わ

れた場合は関数を返し、グローバル変数として使われた場合はグローバル変数の値を返す

– (list 0 1 2)と(funcall (symbol-function 'list) 0 1 2))はだいたい同じ

Page 3: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

Symbol

FOO package

IOTAFLATTENGROUP-HEADED…

> (iota 3) => (0 1 2)> iota => 72

symbol-function(lambda (n)(loop for i from 0 upto (1- n) collect i))

symbol-value72

symbol-package#<PACKAGE “FOO”>

symbol-name“IOTA”

symbol-plist()

Page 4: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

Symbol

BAR package

ALPHABETA...IOTA…

> (iota 3) => NIL> iota => “i”

symbol-function(lambda (str) (and (stringp str) (string= “i” str)))

symbol-value“i”

symbol-package#<PACKAGE “BAR”>

symbol-name“IOTA”

symbol-plist()

Page 5: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

Current Package

BAR package

ALPHABETA…IOTA...

FOO package

IOTAFLATTENGROUP-HEADED…

カレントパッケージがFOOの場合

> (iota 3) => (0 1 2)カレントパッケージがBARの場合

> (iota 3) => NIL

カレントパッケージは*PACKAGE*の値で制御

カレントパッケージの切り替えはIN-PACKAGEで行うのが無難

例) (in-package :chat-with-tree)

Page 6: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

DEFPACKAGE● パッケージを定義する● 他のパッケージに所属しているシンボルで使いたいシンボルがあったらその

パッケージをUSEするか、シンボルを直接指定してIMPORTする。

● (defpackage :chat-with-tree (:use :cl :chiku.util))

● これで、カレントパッケージがCHAT-WITH-TREEの場合には

CHIKU.UTILパッケージの外部シンボルがすべて使える

● (defpackage :chat-with-tree (:use :cl) (:import-from :chiku.util :aif :it))– これはCHIKU.UTILパッケージから2つのシンボル、AIFとITだけ使う場合

Page 7: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

今日の主題はPackage入門ではありません

Page 8: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

参考書

● パッケージの説明はPractical Common Lispの21章が素晴らしい

– 邦訳版:実践Common Lisp● ただし、Practical Common Lispはシンボルの説明

があんまりわかりやすくないというか、まとまっていない

● シンボルの説明はANSI Common Lispの第8章がよく

まとまっている

– 邦訳版:ANSI Common Lisp

Page 9: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

ズボラなDEFPACKAGE(defpackage :chiku.register (:use :cl :chiku.util :sqlite :cl-fad :split-sequence :sb-ext))

どのパッケージからどんなシンボルを使ってるのかがさっぱりわからない → 読む人にやさしくない

Page 10: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

律儀なDEFPACKAGE

● 書くのが面倒

● 以下の2箇所で意思表示しなくちゃいけない

– DEFPACKAGE– 実際の使用

(defpackage :chiku.register (:import-from :common-lisp :defpackage :in-package :defparameter :merge-pathnames :defun :cadr :position :subseq :car :list :string= :ignorable :declare :quote :stringp :if :&rest :destructuring-bind :&body :defmacro :defgeneric :defclass :defmethod :call-next-method :append :t :make-instance :length :- :make-list :zerop :remove-if :gethash :push :dolist :equal :function :make-hash-table :let :lambda :mapcar :nreverse :reduce :maphash :rename-file :delete-file :apply :mapc :namestring) (:import-from :chiku.util :str<-textfile :concat-str :once-only :str-case :_ :papply :itoa :drop) (:import-from :sqlite :execute-single :disconnect :execute-to-list :execute-non-query :connect) (:import-from :split-sequence :split-sequence) (:import-from :cl-fad :pathname-as-directory :copy-file) (:import-from :sb-ext :*posix-argv* :run-program))

Page 11: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

問題点

● 2箇所以上で意思表示するのはかなりまずい– 修正が難しいから、そして面倒だから

● ロジックを記述している瞬間はどのシンボルを使ってるのか理解しているはずだから、実際の使用が優先されるべき– どのシンボルを使っているのか履き違えている場合は、ロ

ジックを正しく記述できない

● シンボルはオブジェクトで、パッケージもオブジェクト、つまりLISPで扱える。

 →ズボラver.から律儀ver.を生成できる

Page 12: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

ズボラver.から律儀ver.を作る

● シンボルは自分の出自を知っているので、実装はすごく簡単● ソースコードから式を読み、シンボルだけ取り出して各シンボルの所属

パッケージを調べる

– READ– FLATTEN, REMOVE-IF-NOT, REMOVE-DUPLICATE– SYMBOL-PACKAGE

● 手書きの時は、インターンされずかつ書きやすいKeyword Symbolが手軽だが、自動生成なら文字列が便利

– SYMBOL-NAME, PACKAGE-NAME– Keyword Symbolの方がかっこいいという感性の人は、KEYWORDパッ

ケージへINTERNすればOK

Page 13: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

ちょっとした問題

● 新しく起動したREPLで単にファイルをLOADして律儀ver.の生成、とやっても

うまくいかない

● つまり、よそから持って来たライブラリのDEFPACKAGEがズボラver.で書か

れていても、単にLOADして律儀ver.の出力、とやってもうまく行かない。

● READはシンボルをカレントパッケージにインターンしようとする

– カレントパッケージを変更した上で出力すれば問題ない

– (load “sample.lisp”)(let ((*package* (find-package :chiku.register))) (recompose-defpackage :chiku.register “sample.lisp”))

Page 14: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

ズボラのススメ

● ソースコードは静的なものなので、この結果を貼りこむのは本質的に手動

– LISPオブジェクトじゃない、LISPの外という意味

– 公開するソースコードのDEFPACKAGEフォームをこのやり方で生成して貼

りこむ、という使い方自体はできる

● むしろ、ズボラver.以外書かない方針を提唱したい

– 律儀ver.は簡単な手順で生成できる

● LISPに聞いてわかることをわざわざ書かない、書かせない

● ソースコード(読む用の)もテキストじゃなくLISPオブジェクトとして

配布できたらいいと思う。– 危ないけど

Page 15: Before LISPs Just Part of the Past #3 ~ Irritating packages ~

その他の細々したこと

● あるパッケージをIN-PACKAGEするファイルが複数ある場合

● IN-PACKAGEが書かれていないファイルがある場合

● 1つのファイルでIN-PACKAGEが複数回行われている場合

● LOADが好ましくない副作用を持つ場合

● ズボラと律儀の間にあるDEFPACKAGE● EXPORT節などの取り扱い

● 神は細部に宿ります