ラベル 実践CL の投稿を表示しています。 すべての投稿を表示
ラベル 実践CL の投稿を表示しています。 すべての投稿を表示

2009年2月15日日曜日

【実践CL】22 黒帯のためのLOOP

拡張loopは好みがわかれるらしい。私はどうか、というと「便利ならいいじゃん」という感じ。便利かどうかちょこっと試してみる。

;;;
;;; 22 黒帯のためのLOOP
;;;

;; 説明よりも、コードサンプルを中心に考える。

;; 22.1 LOOPのパーツ

;; 特になし


;; 22.2 反復の制御

;; この例は動かせない。
;; (loop
;; for item in list
;; for i from 1 to 10
;; do (something))


;; 22.3 数えるループ

(loop for i upto 10 collect i)
; (0 1 2 3 4 5 6 7 8 9 10)
(loop for i downto -10 collect i)
; Error: Don't know where to start stepping.
(loop for i from 0 downto -10 collect i)
; (0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10)


;; 22.4 コレクションやパッケージについてループする。

(loop for i in (list 3 4 5 6) collect i)
; (3 4 5 6)
(loop for i in (list 3 4 5 6) by #'cddr collect i)
; (3 5)
(loop for i on (list 3 4 5 6) collect i)
; ((3 4 5 6) (4 5 6) (5 6) (6))
(loop for i on (list 3 4 5 6) by #'cddr collect i)
; ((3 4 5 6) (5 6))

(loop for x across "abcd" collect x)
; (#\a #\b #\c #\d)

(defparameter *v* excl::*package-table*)

(loop for x across *v* collect x)
; (NIL #<The COMMON-LISP package> #<The KEYWORD package> #<The EXCL package> #<The ACLMOP package> #<The SYSTEM package>
; #<The GARBAGE package> #<The COMMON-LISP-USER package> #<The TOP-LEVEL package> #<The COMPILER package> #<The FOREIGN-FUNCTIONS package>
; #<The DEBUGGER package> #<The MULTIPROCESSING package> #<The DEFSYSTEM package> #<The LEP package> #<The LEP-IO package>
; #<The NULL-PACKAGE-REPLY-SESSION package> #<The ACL-SOCKET package> #<The EXCL.SCM package> #<The CROSS-REFERENCE package>
; #<The PROFILER package> #<The INSPECT package> #<The NET.URI package> #<The ASDF package> #<The UTIL.AKA package>
; #<The ALEXANDRIA.0.DEV package> #<The CXML-SYSTEM package> #<The TRIVIAL-GRAY-STREAMS-SYSTEM package>
; #<The CLOSURE-COMMON-SYSTEM package> #<The PURI-SYSTEM package> #<The TRIVIAL-GRAY-STREAMS package> #<The BABEL-ENCODINGS package>
; #<The BABEL package> #<The RUNES package> #<The UTF8-RUNES package> #<The RUNES-ENCODING package> #<The HAX package> #<The PURI package>
; #<The CXML package> #<The SAX package> #<The CXML-XMLS package> #<The KLACKS package> #<The DOM package> #<The RUNE-DOM package>
; #<The DOMTEST package> #<The DOMTEST-TESTS package> #<The XMLCONF package> NIL NIL NIL)


;; 処理系が使っているハッシュテーブルを探す。
(do-all-symbols (sym)
(when (handler-case
(symbol-value sym)
(condition (c) nil))
(when (typep (symbol-value sym) 'hash-table)
(print sym))))
; ACL-SOCKET::*HOSTNAME-CACHE*
; ACL-SOCKET::*IPADDR-CACHE*
; ACL-SOCKET::*PORT-CACHE*
; ASDF::*DEFINED-SYSTEMS*
; BABEL::*STRING-VECTOR-MAPPINGS*
; BABEL-ENCODINGS::*ABSTRACT-MAPPINGS*
; BABEL-ENCODINGS::*CHARACTER-ENCODINGS*
; COMPILER::*LOC-PARAM-CONS*
; CXML:*DTD-CACHE*
; EXCL::*ADVISE-HASH-TABLE*
; EXCL::*EQL-SPECIALIZER-TABLE*
; EXCL::*PACKAGE-NAMES*
; EXCL::*LAP-EMITTERS*
; EXCL::*FSPEC->PATHNAME*
; EXCL::.SAVED-ENTRY-POINTS.
; EXCL::*PATHNAME->FSPECS*
; EXCL::*LONG-METHOD-COMBINATION-FUNCTIONS*
; EXCL::*PREVIOUS-NWRAPPERS*
; EXCL::*ARG-INFO-TABLE*
; EXCL::*EF-DUAL-CHANNEL-FUNCTIONS*
; EXCL::*FWRAP-HASH-TABLE*
; EXCL::*SHARED-ESLOTS*
; EXCL::*EF-SINGLE-CHANNEL-FUNCTIONS*
; EXCL::*LOGICAL-PATHNAME-TRANSLATIONS*
; EXCL::*SETF-FUNCTION-HASHTABLE*
; EXCL::*XP-PARSER-TABLE*
; EXCL::*PROPERTY-HASH-TABLE*
; EXCL::*EF-SINGLE-CHANNEL-DIRECT-FUNCTIONS*
; EXCL::*FIND-CLASS*
; EXCL::*NAME-TO-CHAR-TABLE*
; EXCL::*ENCAPSULATION-HASH-TABLE*
; EXCL::*SHARED-CONS-TABLE*
; EXCL::.SET-READTABLES.
; EXCL.SCM::*CHANGED-DEFINITIONS*
; EXCL.SCM::*FILE-SECTIONS*
; FOREIGN-FUNCTIONS::*ANON-IFTYPE-CACHE*
; NET.URI::*URIS*
; PURI::*URIS*
; RUNES::*RUNE-NAMES*
; RUNES-ENCODING::*NAMES*
; RUNES-ENCODING::*ENCODINGS*
; RUNES-ENCODING::*CHARSETS*
; TOP-LEVEL::*COMMAND-HASH-TABLE*
; NIL


(loop for k being the hash-keys in excl::*package-names* collect k)
; ("" "MULTIPROCESSING" "SI" "FOREIGN-FUNCTIONS" "CL-USER" "CXML-SYSTEM" "CL" "DEBUG" "DS" "NET.URI" ...)

(loop for k being the hash-keys in excl::*package-names* (hash-value v) collect v)
; (#<The KEYWORD package> #<The MULTIPROCESSING package> #<The SYSTEM package>
; #<The FOREIGN-FUNCTIONS package> #<The COMMON-LISP-USER package> #<The CXML-SYSTEM package>
; #<The COMMON-LISP package> #<The DEBUGGER package> #<The DEFSYSTEM package> #<The NET.URI package> ...)
(loop for v being the hash-values in excl::*package-names* collect v)
; (#<The KEYWORD package> #<The MULTIPROCESSING package> #<The SYSTEM package>
; #<The FOREIGN-FUNCTIONS package> #<The COMMON-LISP-USER package> #<The CXML-SYSTEM package>
; #<The COMMON-LISP package> #<The DEBUGGER package> #<The DEFSYSTEM package> #<The NET.URI package> ...)

(loop for sym being the symbols in (find-package :cl) collect sym)
; (COMMON-LISP::P LOGCOUNT TIME ARITHMETIC-ERROR-OPERANDS NSUBST CHANGE-CLASS MAPHASH EVAL-WHEN BLOCK MEMBER-IF ...)

(loop for sym being the symbols in (find-package :cl) count sym)
; 978

(loop for sym being the present-symbols in (find-package :cl) count sym)
; 978

(loop for sym being the external-symbols in (find-package :cl) count sym)
; 977

(loop for sym being the external-symbols in (find-package :excl) count sym)
; 588

(loop for sym being the present-symbols in (find-package :excl) count sym)
; 6947

(loop repeat 5) ; NIL
(loop repeat 5
for x = 0 then (1+ x)
collect x) ; (0 1 2 3 4)
(loop repeat 5
for x = 0 then y
for y = 1 then (+ x y)
collect y) ; (1 2 4 8 16)

(loop repeat 3 for k being the hash-keys in excl::*package-names* collect k)
; ("" "MULTIPROCESSING" "SI")

;; 22.6 ローカル変数

;; 特になし


;; 22.7 変数を分配する

(loop for (a b) in '((1 2) (3 4) (5 6))
do (format t "a: ~a; b: ~a~%" a b))
; a: 1; b: 2
; a: 3; b: 4
; a: 5; b: 6
; NIL

(loop for cons on (list 1 2 3 4 5)
do (format t "~a" (car cons))
when (cdr cons) do (format t ", "))
; 1, 2, 3, 4, 5
; NIL

(loop for (item . rest) on (list 1 2 3 4 5)
do (format t "~a" item)
when rest do (format t ", "))
; 1, 2, 3, 4, 5
; NIL

(defparameter *random* (loop repeat 100 collect (random 1000)))

(loop for i In *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))
; (0 998 54241 59 41)



;; 22.9 無条件実行

(loop for i from 1 to 10 do (print i))
; 1
; 2
; 3
; 4
; 5
; 6
; 7
; 8
; 9
; 10
; NIL

(block outer
(loop for i from 0 return 100)
(print "This will print")
200)
; "This will print"
; 200

(block outer
(loop for i from 0 do (return-from outer 100))
(print "This won't print")
200) ; 100


;; 22.10 条件実行

(loop for i from 1 to 10 do (when (evenp i) (print i)))
; 2
; 4
; 6
; 8
; 10
; NIL

(loop for i from 1 to 10 when (evenp i) sum i)
; 30

(loop for key in (list "CXML" "RUNE" "CL" "DEBUG" "HOGE" "PIYO")
when (gethash key excl::*package-names*) collect it)
; (#<The CXML package> #<The COMMON-LISP package> #<The DEBUGGER package>)


;; 22.11 セットアップと後始末

(loop named outer for p across excl::*package-table*
do (when p
(loop for sym being the symbols in p
do (if (equal "CAR" (symbol-name sym))
(return-from outer p))))) ; #<The COMMON-LISP package>


;; 22.12 終了条件のテスト

(if (loop for n in (list 1 2 3 4) always (evenp n))
(print "All numbers even.")) ; NIL

(if (loop for n in (mapcar #'(lambda (n) (* 2 n)) (list 1 2 3 4)) always (evenp n))
(print "All numbers even.")) ; "All numbers even."

(if (loop for n in (list 1 3 11 17) never (evenp n))
(print "All numbers odd.")) ; "All numbers odd."

(loop for char across "abc123" thereis (digit-char-p char)) ; 1
(loop for char across "abcdef" thereis (digit-char-p char)) ; NIL


;; 22.13 まとめ

特になし。

loop、便利だなぁ。

お、やっと後半戦に入れる。後半戦は実践の章。
こつこつ。

【実践CL】21 大規模開発に向けて:パッケージとシンボル

パッケージとシンボルは、いろんな機会で自分なりに整理してきたので、軽く復習というノリで。


;;;
;;; 21 大規模開発に向けて:パッケージとシンボル
;;;


;; 21.1 読取器はパッケージをどうやって使うか

*package* ;#<The COMMON-LISP-USER package>
(find-symbol "CAR") ;CAR, :INHERITED
(find-symbol "CAR" (find-package "COMMON-LISP"))
;CAR, :EXTERNAL
(find-symbol "car") ;NIL, NIL

(find-symbol "PIYO") ;NIL, NIL
(intern "PIYO") ;PIYO, NIL
(find-symbol "PIYO") ;PIYO, :INTERNAL

(eql ':foo :foo) ;T

(symbol-name :foo) ;"FOO"

(eql '#:foo '#:foo) ;NIL

(symbol-name '#:foo) ;"FOO"
(symbol-package '#:foo) ;NIL

(defparameter *pair-1* (cons '#:foo (intern "FOO")))
(defparameter *pair-2* (cons '#:foo (intern "FOO")))

(eql *pair-1* *pair-2*) ;NIL
(equal *pair-1* *pair-2*) ;NIL
(equal (car *pair-1*) (car *pair-2*)) ;NIL

(eql (car *pair-1*) (car *pair-2*)) ;NIL
(eql (cdr *pair-1*) (cdr *pair-2*)) ;T

(setf (symbol-value (car *pair-1*)) 1) ;1
(symbol-value (car *pair-1*)) ;1

(defparameter *a* '#:foo)
(type-of *a*) ;SYMBOL
(symbol-value *a*) ;Error: Attempt to take the value of the unbound variable `#:FOO'.
(setf (symbol-value *a*) 10)
(symbol-value *a*) ;10

(defparameter *b* *a*)
(symbol-value *b*) ;10

(gensym) ;#:G7


;; 21.2 パッケージとシンボルの用語をいくつか

;; 特になし。


;; 21.3 3つの標準パッケージ

*package* ; #<The COMMON-LISP-USER package>
common-lisp:*package* ; #<The COMMON-LISP-USER package>
cl:*package* ; #<The COMMON-LISP-USER package>
:a ;:A
keyword:a ;:A
(eql :a keyword:a) ;T


;; 21.4 自分でパッケージを定義する

(defpackage :util.aka
(:use :common-lisp))

excl::*package-table*

(in-package :util.aka)


;; 21.5 再利用可能なライブラリのパッケージ化

(defpackage :util.aka
(:use :common-lisp)
(:export :open-db
:save
:store))

;; 21.6 個別の名前をインポートする

;; On REPL
(in-package :util.aka)
(asdf:operate 'asdf:load-op :cxml)
(defpackage :util.aka
(:use :common-lisp)
(:import-from :cxml :parse))
(find-symbol "PARSE") ;PARSE, :INTERNAL

(defpackage :util.aka
(:use :common-lisp :cxml)
(:shadow :parse))


;; 21.7 パッケージ化の定石

;; 特になし

;; 21.8 パッケージの悩みどころ

;; 特になし


こつこつ。

2009年2月12日木曜日

【実践CL】20 特殊オペレータ

特殊オペレータは多少まじめにやってみた。
コンパイルはまったく理解していないので途中で力尽きた。


;;;
;;; 20 特殊オペレータ
;;;

;; 20章は例が少ない。即興で自分で例を作成していくことにする。
;; また自分なりのコメントもつける。

;; 何がspecial operatorかは、数学の公理のように選択である。
;; 言語を仕様化するには公理を選択するのが簡便である。


;; 20.1 評価を制御する。

(mapcar #'special-operator-p '(quote if progn))
; 3

;; quote
;; quoteはreaderが作ったLisp Objectを返す。
;; 別の言い方をすれば、evalを迂回する。

(car (quote (cdr nil))) ; CDR
(car (cdr nil)) ; NIL

;; if
;; ifはLispの基本評価ルールから逸脱する。


(defun if-func (condition true-clause false-clause)
(if condition
true-clause
false-clause))

(if-func nil
(car 10)
(cdr nil))
;; (car 10)が先に評価されるのでerrorになる。

(if nil
(car 10)
(cdr nil))
;; (car 10)が評価されるのは条件がnon-nilのときのみ。
;; よってerrorにならない。


;; progn
;; Lispの基本評価ルールから逸脱して、並列した式を評価する。
;; ある処理をprognで書くということはそれが副作用を目的としている
;; ということである。

;; 通常の評価は再帰的に単一のLisp formを評価するのみ。
(map 'vector #'1+
(append (cdr (list 1 2 3))
(car '((10 20) 30))))

;; prognは複数のLisp formを順次評価する。
(progn
(print 1)
(print 2)
(print 3))

;; ふと疑問。ファイルをloadすると文書内の文字列が
;; read evalされていくが、その順次処理はprognなのだ
;; ろうか。違うな。loadは関数で、ストリームのeofに
;; なるまで、read、evalを繰り返しているだけだろう。
;; 逆にprognというのが、prognの範囲において、そのよ
;; うな動作をする特殊オペレータということなのだろう。


;; 20.2 レキシカル環境を操作する

;; レキシカル環境が何かということを考える観点のひと
;; つにそれがevalの内部機構であるということがある。
;; Lispをしているとき、evalは2つある。1つはプログラ
;; マの頭の中。もうひとつは計算機の中だ。

;; 計算機でevalを実現するということは、ハードウエア
;; だけで組み立てるにせよ、ハードウエアとソフトウエ
;; アで組み立てるにせよ、ソフトウエアとしてどこから
;; Lisp自身で組み立てるかにせよ、いずれにせよ何か
;; Lisp以外のものも使いつつevalを作らなければいけな
;; い。

;; そのときのevalの構成物のひとつがレキシカル環境だ。

;; なので、レキシカル環境にプログラマがアクセスする
;; ことは、REPLでそれ以外のLisp formやLispオブジェ
;; クトを取り扱うのを越えた「意味」をもっている。


(mapcar #'special-operator-p '(let let* function setq flet labels macrolet symbol-macrolet))
; 8 3
(let ((v 1))
(incf v))
;; vは評価されず、レキシカル環境の変数名となる。vに
;; は1がbindされる。evalは、let式の中ではvという記
;; 号を変数名として取り扱い、vを評価すると変数に
;; bindされた値を返すように振る舞う。

(setq v 1) ;このsetqは特殊オペレータだがアクセスしているのはレキシカル環境ではない。
(let ((v 10)
(w (incf v)))
(incf w)) ; 3

(setq v 1)
(let* ((v 10)
(w (incf v)))
(incf w)) ; 12
;; letとlet*では、レキシカル変数を生成するときの評
;; 価ルールが異なる。


(flet ((add-10 (n)
(incf n 10)))
(add-10 100)) ; 110
;; fletはletの関数版。

(defun add-10 (n)
(incf n 2))
(add-10 1) ; 3
(flet ((add-10 (n)
(if (< n 10)
(add-10 (incf n))
n)))
(add-10 1)) ; 4
(labels ((add-10 (n)
(if (< n 10)
(add-10 (incf n))
n)))
(add-10 1)) ; 10
;; fletとflabelsの関係はletとlet*のごとし。

;; fletとflabelsはそれが置かれた場所(lexical)の環境
;; にアクセスできるので、top-levelで定義する関数と
;; 比べると、そこでの文脈に依存した簡潔な記述が可能
;; となる。

;; function
;; symbolまたはlambda expressionから関数オブジェクトを取り出す。

(function car) ; #
(function (lambda (x) x)) ; #

;; ところで関数って何だっけ?

;; 関数(関数オブジェクト)はLispオブジェクトであり、
;; 基本評価ルールとして、lisp formのcarに位置したと
;; きは、evalによって、cdrを情報として渡される。(こ
;; の処理を特殊オペレータにしたのがfunctionかなぁ)
;; 渡された情報とLispオブジェクト内の定義に従って処
;; 理を実行して値を返す。

;; 関数はclosureを成す場合と成さない場合がある。

(defun hoge (x) x)
(type-of #'hoge)
(symbol-function 'hoge) ; function
(type-of #'hoge) ; FUNCTION
(defun make-piyo ()
(let ((v 0))
#'(lambda (x) x)))
(setf (symbol-function 'piyo) (make-piyo))
(symbol-function 'piyo) ; interpreted closure
(type-of #'piyo) ; FUNCTION


;; macro

;; Common Lispにはmacroと名のつくものがたくさんある。
;; 代表的なものは次のとおり。
;;
;; - macro
;; - compiler macro
;; - reader macro
;; - dispatching macro
;; - symbol macro
;;
;; macroなんぞや、を書く気力は今はないので割愛。

;; macrolet
;; macroletは、defunに対するfletがごとく、defmacroに対する。

;; macroletの例は思いつかなかったのでCLtL2より。
(defun foo (x flag)
(macrolet ((fudge (z)
`(if flag
(* ,z ,z)
,z)))
(+ x
(fudge x)
(fudge (+ x 1)))))

(foo 2 nil) ; 7
(foo 2 t) ; 15


;; symbol-macroletは、同様に、define-symbol-macroに対する。

(symbol-macrolet ((hoge 'piyo)
(moge #'car))
(list hoge moge hoge moge)) ; (PIYO # PIYO #)


;; 20.3 ローカルなフローの制御

(mapcar #'special-operator-p '(block return-from tagbody go))
; 4 8 3

;; block, return-from
;;

(block outer
(print 'outer-1)
(block inner
(print 'inner-1)
(return-from inner)
(print 'inner-2)
)
(print 'outer-2))

(tagbody
(go bottom)
top
(print 'top)
(go out)
middle
(print 'middle)
(go top)
bottom
(print 'bottom)
(go middle)
out)


;; 20.4 スタックの巻き戻し
(mapcar #'special-operator-p '(catch throw unwind-protect))
; 3 4 8 3

(defun foo ()
(format t "Entering foo~%")
(block a
(format t " Entering BLOCK~%")
(bar #'(lambda () (return-from a)))
(format t " Leaving BLOCK~%"))
(format t "Leaving foo~%"))

(defun bar (fn)
(format t " Entering bar~%")
(baz fn)
(format t " Leaving bar~%"))

(defun baz (fn)
(format t " Entering baz~%")
(funcall fn)
(format t " Leaving baz~%"))

; CL-USER(58): (foo)
; Entering foo
; Entering BLOCK
; Entering bar
; Entering baz
; Leaving foo
; NIL
; CL-USER(59):

(defparameter *obj* (cons nil nil))
(defun foo ()
(format t "Entering foo~%")
(catch *obj*
(format t " Entering CATCH~%")
(bar #'(lambda () (return-from a)))
(format t " Leaving CATCH~%"))
(format t "Leaving foo~%"))

(defun bar (fn)
(format t " Entering bar~%")
(baz fn)
(format t " Leaving bar~%"))

(defun baz (fn)
(format t " Entering baz~%")
(throw *obj* nil)
(format t " Leaving baz~%"))

; CL-USER(62): (foo)
; Entering foo
; Entering CATCH
; Entering bar
; Entering baz
; Leaving foo
; NIL

;; unwind protect

(defun foo ()
(unwind-protect
(progn
(format t "Entering foo~%")
(block a
(format t " Entering BLOCK~%")
(bar #'(lambda () (return-from a)))
(format t " Leaving BLOCK~%"))
(format t "Leaving foo~%"))
(format t "Unwind-protect foo~%")))

(defun bar (fn)
(unwind-protect
(progn
(format t " Entering bar~%")
(baz fn)
(format t " Leaving bar~%"))
(format t "Unwind-protect bar~%")))

(defun baz (fn)
(unwind-protect
(progn
(format t " Entering baz~%")
(funcall fn)
(format t " Leaving baz~%"))
(format t "Unwind-protect baz~%")))

; CL-USER(64): (foo)
; Entering foo
; Entering BLOCK
; Entering bar
; Entering baz
; Unwind-protect baz
; Unwind-protect bar
; Leaving foo
; Unwind-protect foo
; NIL
; CL-USER(65):


;; 20.5 多値

(mapcar #'special-operator-p '(multiple-value-call multiple-value-prog1))
; 2 3 4 8 3

;; multiple-value-call
(funcall #'+ (values 1 2) (values 3 4)) ; 4
(multiple-value-call #'+ (values 1 2) (values 3 4)) ; 10

;; multiple-value-prog1
(prog1
(values 1 2)
(values 3 4)
(values 5 6)) ; 1

(multiple-value-prog1
(values 1 2)
(values 3 4)
(values 5 6)) ; 1 2



;; 20.6 EVAL-WHEN

(special-operator-p 'eval-when)
; 1 2 3 4 8 3

;; loadは、基本的にはtop-levelの表現を順次評価する。
;; compile-fileは、基本的には表現をcompiled code に
;; コンパイルするのみで評価はしない。
;;
;; ただしsymbol/package関係の表現やmacroなどの一部
;; の表現については、コンパイルの前作業として評価し
;; ないと正しくコンパイルできない。
;;
;; この問題を解決することを動機として、何を何時評価
;; するかを指定する方法がeval-whenである。


;; コンパイルのことを考えるには、まずトップレベルを
;; 明確にしなければならない。

;; トップレベルとは、処理系が持つREPLである。この
;; REPLを介してプログラマと処理系は対話する。もちろ
;; んそれはスタートポイントであり、プログラムを組ん
;; で別の方法(例えばHTTPとか)で対話するようにしても
;; よい。

;; トップレベルの表現として便利なように、いくつ
;; かの特殊オペレータは設計されている。

;; loadでソースファイルを読み込むのはソースファイル
;; の表現を順次手で入力していくのと似たようなもので
;; ある。違う点は、REPLじゃなくてRELであるというこ
;; とだ。

;; ではコンパイル。

;; まずcompileが何かを確認する。compileとは、関数ま
;; たはdefmacroのマクロを処理系においてより処理効率
;; がよい言語に翻訳する関数である。

(defun hoge (x) x)

(symbol-function 'hoge) ; interpreted function hoge
(compile 'hoge) ; HOGE nil nil
(symbol-function 'hoge) ; function hoge
(disassemble 'hoge)
; ;; disassembly of #
; ;; formals: X

; ;; code start: #x1000ec1328:
; 0: 48 83 f8 01 cmp rax,$1
; 4: 74 01 jz 7
; 6: 06 (push es) ; SYS::TRAP-ARGERR
; 7: 41 80 7f a7 00 cmpb [r15-89],$0 ; SYS::C_INTERRUPT-PENDING
; 12: 74 01 jz 15
; 14: 17 (pop ss) ; SYS::TRAP-SIGNAL-HIT
; 15: f8 clc
; 16: 4c 8b 74 24 10 movq r14,[rsp+16]
; 21: c3 ret
(function-lambda-expression #'hoge) ; (LAMBDA (X) (BLOCK HOGE X)) NIL HOGE


(defmacro piyo (x) x)
(symbol-function 'piyo) ; macro piyo
(macroexpand-1 '(piyo 3)) ; 3 T
(compile 'piyo) ; PIYO nil nil
(symbol-function 'piyo) ; macro piyo
(disassemble 'piyo)
; ;; disassembly of #
; ;; formals: EXCL::**MACROARG** EXCL::..ENVIRONMENT..
; ;; constant vector:
; 0: X
; 1: (X)

; ;; code start: #x1001256328:
; 0: 48 81 ec 98 00 subq rsp,$152 ; 19
; 00 00
; 7: 4c 89 74 24 08 movq [rsp+8],r14
; 12: 48 83 f8 02 cmp rax,$2
; 16: 74 01 jz 19
; 18: 06 (push es) ; SYS::TRAP-ARGERR
; 19: 41 80 7f a7 00 cmpb [r15-89],$0 ; SYS::C_INTERRUPT-PENDING
; 24: 74 01 jz 27
; 26: 17 (pop ss) ; SYS::TRAP-SIGNAL-HIT
; 27: 48 8b d7 movq rdx,rdi
; 30: 48 89 94 24 80 movq [rsp+128],rdx ; EXCL::**MACROARG**
; 00 00 00
; 38: 48 c7 c7 08 00 movq rdi,$8 ; 1
; 00 00
; 45: 48 c7 c6 08 00 movq rsi,$8 ; 1
; 00 00
; 52: 49 8b 8f 67 fd movq rcx,[r15-665] ; :MACRO
; ff ff
; 59: 49 8b af 77 fd movq rbp,[r15-649] ; EXCL::DT-MACRO-ARGUMENT-CHECK
; ff ff
; 66: b0 04 movb al,$4
; 68: ff d3 call *ebx
; 70: 48 8b bc 24 80 movq rdi,[rsp+128] ; EXCL::**MACROARG**
; 00 00 00
; 78: 41 ff 57 67 call *[r15+103] ; SYS::QCDR
; 82: 48 89 7c 24 78 movq [rsp+120],rdi ; #:|g47|
; 87: 49 8b 76 36 movq rsi,[r14+54] ; X
; 91: 49 8b af 5f fd movq rbp,[r15-673] ; EXCL::CAR-FUSSY
; ff ff
; 98: ff 53 d0 call *[rbx-48]
; 101: 48 89 bc 24 88 movq [rsp+136],rdi ; X
; 00 00 00
; 109: 48 8b 7c 24 78 movq rdi,[rsp+120] ; #:|g47|
; 114: 41 ff 57 67 call *[r15+103] ; SYS::QCDR
; 118: 48 8b f7 movq rsi,rdi
; 121: 49 8b 56 3e movq rdx,[r14+62] ; (X)
; 125: 33 ff xorl edi,edi
; 127: 49 8b af 57 fd movq rbp,[r15-681] ; EXCL::LAMBDASCAN-MAXARGS
; ff ff
; 134: b0 03 movb al,$3
; 136: ff d3 call *ebx
; 138: 48 8b bc 24 88 movq rdi,[rsp+136] ; X
; 00 00 00
; 146: f8 clc
; 147: 48 8d a4 24 98 leaq rsp,[rsp+152]
; 00 00 00
; 155: 4c 8b 74 24 10 movq r14,[rsp+16]
; 160: c3 ret
; 161: 90 nop

;; おあそびを少々
(compile 'foo '(lambda (x) x)) ; FOO NIL NIL
(symbol-function 'foo) ; function foo
(foo 3) ; 3
(compile nil '(lambda (x) x)) ; Function anonymous lambda NIL NIL
(setq foo (compile nil '(lambda (x) x)))
(funcall foo 3) ; 3
(setq bar #'(lambda (x) x))
(funcall bar 3) ; 3
(setf bar (compile nil (symbol-value 'bar)))
(funcall bar 3) ;3

;; compileしたcompiled functionはsymbolに格納される。
;; すなわちsymbolの中に関数本体が格納されているとい
;; うことはInterpreted functionだろうがCompiled
;; functionだろうが変わらない。いずれにしても
;; functionを使うということは、REPL上またはソースファ
;; イル上でその関数を呼び出すような表現を記述すると
;; いうことにすぎない。そして、その表現をLisp form
;; に変換した上で評価する際にいずれにしても関数コー
;; ドが参照されて、evalがそれを*利用して*評価を実行
;; するのだ。

;; このcompileがCommon Lispのコンパイルの基礎になる。

;; 続いてcompile-file。

;; あるソースファイルをそのままloadしたときと、
;; compile-file した上でloadしたときとで、処理スピー
;; ドに違いはあって欲しいが、処理内容に違いはあって
;; 欲しくない。

;; loadの仕様は、上記のようにトップレベルの表現を順
;; 次評価する、ということだ。二者で差異が発生しない
;; ようにするにはcompile-fileの仕様をどうすればよい
;; か。

;; まず*package*がソースをloadするときもCompile済み
;; のコードをloadするときも同じでなければならない。
;; ソースの中に*package*に係わる表現が存在しないな
;; らば、それはプログラマの手順の課題である。loadす
;; るときの*package*がずれないようにする。ソースの
;; 中で*package*に係わる記述がある場合は、それ以降
;; のソースにずれがないようにするにはソースのかきぶ
;; りの課題でありそれを実現するのがeval-whenだ。

;; また、compile-fileした時の処理系の状態とloadする
;; ときの処理系の状態も差異がないようにすべきである。
;; 具体的には、compile-fileするときに利用可能となっ
;; ている外部シンボルは、loadするときにも利用可能で
;; あるようにプログラマは手順を配慮すべきである。

;; 。。。 だめだ。途中で力つきた。

;; コンパイルはいつかちゃんとやろう。。。



;; 20.7 その他の特殊オペレータ

(mapcar #'special-operator-p '(locally the load-time-value progv))
; 4 2 1 3 4 8 3
; (+ 4 2 1 3 4 8 3)

;; locally
(defun sample-function (y) ; this y is regarded as special
(declare (special y))
(let ((y t)) ; this y is regarded as lexical
(list y
(locally (declare (special y))
;; this next y is regarded as special
y))))
(sample-function nil) ; (T NIL)


;; the

(the symbol 'a)
(the fixnum 1)
(the (values) (values 1 2))
(the (values integer) (values 1 2))
(the (values integer float symbol) (values 1 2.0 'a))
(the (values integer float symbol) (values 1 2 3)) ; error


;; load-time-value
(defvar *loaded-at* (get-universal-time))
(defun when-loaded () *loaded-at*)

(defun when-loaded () (load-time-value (get-universal-time)))
(when-loaded)

;; progv

(setq x 10
y 20)
(progv '(x y) '(1 2)
(list x y)) ; (1 2)
(list x y) ; (10 20)

(defun hoge ()
(+ nanja konja))
(progv '(nanja konja) '(1 2)
(hoge)) ; 3
(let ((nanja 1) (konja 2))
(hoge)) ; error

こつこつ。

2009年2月9日月曜日

【実践CL】18 FORMATの手習い

formatについてこの章のように多様なサンプルを掲載している書籍は少ないと思う。そういう意味で貴重なもの。

ただしformatのある意味さわりを紹介しているにすぎない。がっちりやるならCLtL2か。
とりあえず、実践CLに沿って自分なりに早見表をまとめてみた。(実践CLまんまではない)

(format nil "~$" pi) ; "3.14"
(format nil "~5$" pi) ; "3.14159"
(format nil "~v$" 3 pi) ; "3.142"
(format nil "~#$" pi) ; "3.1"
(format nil "~#$" pi 'a) ; "3.14"
(format nil "~#$" pi 'a 'b) ; "3.142"
(format nil "~a ~#$" 'a pi 'b) ; "A 3.14"
(format nil "~2,4$" pi) ; "0003.14"

(format nil "~f" pi) ; "3.141592653589793d0"
(format nil "~,5f" pi) ; "3.14159"
(format nil "~e" pi) ; "3.141592653589793d+0"
(format nil "~,4e" pi) ; "3.1416d+0"
(format nil "~,4e" (* 10 pi)) ; "3.1416d+1"

(format nil "~d" 1000000) ; "1000000"
(format nil "~:d" 1000000) ; "1,000,000"
(format nil "~@d" 1000000) ; "+1000000"
(format nil "~@d" -1000000) ; "-1000000"
(format nil "~:@d" -1000000) ; "-1,000,000"
(format nil "~12d" 1000000) ; " 1000000"
(format nil "~12,'0d" 1000000) ; "000001000000"
(format nil "~4,'0d-~2,'0d-~2,'0d" 2005 6 10) ; "2005-06-10"
(format nil "~,,'.,4:d" 1000000) ; "100.0000"

(format nil "~x" 1000000) ; "f4240"
(format nil "~o" 1000000) ; "3641100"
(format nil "~b" 1000000) ; "11110100001001000000"


(format nil "The value is: ~a" 10) ; "The value is: 10"
(format nil "The value is: ~a" "foo") ; "The value is: foo"
(format nil "The value is: ~a" (list 1 2 3)) ; "The value is: (1 2 3)"

(format nil "Syntax error. Unexpected character: ~:c" #\a) ; "Syntax error. Unexpected character: a"
(format nil "~@c~%" #\a) ;"#\\a
;"
(format nil "~:@c" (code-char 0)) ; "null"

(format nil "~r" 1234) ; "one thousand two hundred thirty-four"
(format nil "~:r" 1234) ; "one thousand two hundred thirty-fourth"
(format nil "~@r" 1234) ; "MCCXXXIV"
(format nil "~:@r" 1234) ; "MCCXXXIIII"

(format nil "file~p" 1) ; "file"
(format nil "file~p" 10) ; "files"
(format nil "file~p" 0) ; "files"

(format nil "~r file~:p" 1) ; "one file"
(format nil "~r file~:p" 10) ; "ten files"
(format nil "~r file~:p" 0) ; "zero files"

(format nil "~r famil~:@p" 1) ; "one family"
(format nil "~r famil~:@p" 10) ; "ten families"
(format nil "~r famil~:@p" 0) ; "zero families"

(format nil "~(~a~) ~a" "AaA" "AaA") ; "aaa AaA"
(format nil "~(~a~)" "AaA bBb") ; "aaa bbb"
(format nil "~@(~a~)" "AaA bBb") ; "Aaa bbb"
(format nil "~:(~a~)" "AaA bBb") ; "Aaa Bbb"
(format nil "~:@(~a~)" "AaA bBb") ; "AAA BBB"

(format nil "~[cero~;uno~;dos~]" 0); "cero"
(format nil "~[cero~;uno~;dos~]" 1); "uno"
(format nil "~[cero~;uno~;dos~]" 2); "dos"
(format nil "~[cero~;uno~;dos~]" 3); ""

(format nil "~[cero~;uno~;dos~:;mucho~]" 3) ; "mucho"
(format nil "~[cero~;uno~;dos~:;mucho~]" 100) ; "mucho"

(defparameter *list-etc*
"~#[NONE~;~a~;~a and ~a~:;~a, ~a~]~#[~; and ~a~:;, ~a, etc~].")

(format nil *list-etc* ) ; "NONE."
(format nil *list-etc* 'a) ; "A."
(format nil *list-etc* 'a 'b) ; "A and B."
(format nil *list-etc* 'a 'b 'c) ; "A, B and C"
(format nil *list-etc* 'a 'b 'c 'd) ; "A, B, C, etc"
(format nil *list-etc* 'a 'b 'c 'd 'e) ; "A, B, C, etc"

(format nil "~:[FAIL~;pass~]" t); "pass"
(format nil "~:[FAIL~;pass~]" nil); "FAIL"

(format nil "~{~a, ~}" (list 1 2 3)) ; "1, 2, 3, "
(format nil "~{~a~^, ~}" (list 1 2 3)) ; "1, 2, 3"
(format nil "~@{~a~^, ~}" 1 2 3) ; "1, 2, 3"


(format nil "~r ~:*(~d)" 1) ; "one (1)"

(format nil "I saw ~r el~:*~[ves~;f~:;ves~]." 0); "I saw zero elves."
(format nil "I saw ~r el~:*~[ves~;f~:;ves~]." 1); "I saw one elf."
(format nil "I saw ~r el~:*~[ves~;f~:;ves~]." 2); "I saw two elves."

(format nil "~{~s~*~^ ~}" '(:a 10 :b 20)) ; ":A :B"

こつこつ。

【実践CL】17 オブジェクト指向再入門:クラス

CLOSSのクラス紹介。なぜ完全なコードを示さず、動かせぬ例で説明を続けるのか理解できない。


  • 17.1 DEFCLASS
  • 17.2 スロット指定子
  • 17.3 オブジェクトの初期化
  • 17.4 アクセサ関数
  • 17.5 WITH-SLOTSとWITH-ACCESSORS
  • 17.6 スロットをクラスに割り当てる (共有スロット)
  • 17.7 スロットと継承
  • 17.8 多重継承
  • 17.9 良きオブジェクト指向設計
  • 特になし。


いつかちゃんとCLOSとオブジェクト指向をやりたい。
こつこつ。

【実践CL】16 オブジェクト指向再入門:総称関数

CLOSをしっかりやるとしたら、実践CLのまとめくらいではおっつかない。
実践CLではさわり程度という感覚でみて、深掘りしない。将来、タイミングを捉えて深掘りするが、そのときは、Javaをやっておかないとまずいと思う。

  • 16.1 総称関数とクラス
  • 16.2 総称関数とメソッド
  • 16.3 DEFGENERIC
  • 特になし。

  • 16.4 DEFMETHOD
  • うーん。オブジェクト指向再入門にあたって、クラスの前にメドッドをやる利点がわからない。奇抜さを狙っているだけじゃないか?この節の例だって、クラスをやってないから自分で試すことができないじゃなか。

  • 16.5 メソッド結合
  • 特になし。

  • 16.6 標準メソッド結合
  • 特になし。

  • 16.7 その他のメソッド結合
  • 16.8 多重メソッド
  • 16.9 次章へつづく……
  • 特になし

こつこつ。

2009年2月8日日曜日

【実践CL】15 実践:パスネーム可搬ライブラリ

やりかけのものに追い込みをかけるモードに。
まず実践CL。

この章はfeaturesの取り扱いと実際に使えるパスネーム可搬ライブラリを作るというお話。

パスネーム可搬ライブラリは、ここで作るものをベースとしてより洗練させたものが、CL-FADとして存在する。clbuildにも含まれている。

http://weitz.de/cl-fad/

こちらはAPIが記述されている(PCLにはない)のでこのAPI仕様にしたがって試してみる。問題なし。

こつこつ。

2009年1月18日日曜日

【実践CL】19 例外処理を越えて:コンディションと再起動

事情によりスキップして19章へ。

  • こんなシチュエーションを想定しているようだ。

    (defun high (...)
    ...
    (medium ...)
    ...)

    (defun medium (...)
    ...
    (low ...)
    ...)

    (defun low (...)
    ...))

  • lowが失敗し、mediumがそれに対応できないことがありえるとする。highをどうしておくべきか。
  • 選択肢1:原因にしたがって、mediumが担当すべきだった作業含めてhighが実施。これはmediumの機能をほぼhighがもっていることになり、なんだか、という点と、この例のような三階層じゃなくて階層が増えたらhighに詰む機能が膨大になるという課題がある。
  • 選択肢2:パッチをあてる。再度mediumがlowを呼び出したときにlowがエラーを出さないようにする処理をhighが実施して再度mediumを呼出す。これも、mediumの内部仕様についてhighを書く人が熟知していることになるので、関数のブラックボックス性から言うと好ましくない。
  • なんかうまい方法があるの? あるよ。それがCLのコンディションシステム。

  • 19.1 Lispのやり方

    • ログを解析する仮想的なソフトウエアを例にLispのやり方を説明する。
    • 状況設定。

      Webサーバのログのようなテキスト形式のログファイルを読むソフトウエア。

      parse-log-entry:
      入力:ひとつのログエントリを含むテキスト
      出力:log-entryオブジェクト

      parse-log-file:
      入力:ひとつのログファイル
      出力:log-entryオブジェクトのリスト


  • 19.2 コンディション

    • 基礎情報。

      • conditionはstandard-objectの系列ではない。
      • conditionオブジェクトは、make-conditionで生成する。
      • conditionオブジェクトの中身へのアクセスはslot-valueではアクセスできない。
      • conditionオブジェクトの定義には、define-conditionを使う。

    • ここの状況での定義。

      ;; parse-log-entryがパースできないテキストを与えられた時に通知するコンディション
      (define-condition malformed-log-entry-error (error)
      ((text :initarg :text :reader text)))


  • 19.3 コンディションハンドラ

    • コンディションの通知はerrorによって実施する。
    • errorの呼び出し方法は2つ。
    • 1:事前にインスタンス化したconditionオブジェクトをerrorの引数にする。
    • 2:コンディションクラスの名前とそれへの引数をerrorの引数にする。
    • ここの状況での定義。

      ;; parse-log-entryのアウトライン
      (defun parse-log-entry (text)
      (if (woll-formed-log-entry-p text)
      (make-instance 'log-entry ...)
      (error 'malformed-log-entry-error :text text)))


    • コンディションが発行されたときに、何が起こるかは、コールスタック上で発行地点(parse-log-entry)より下に何があるかによる。
    • デバッガに入らないためには、どこかでコンディションハンドラを確立している必要がある。
    • コンディションハンドラは、コンディションハンドラ自体とそれを取扱う処理系部分とで理解すべき。
    • コンディションハンドラの基本事項は次のとおり。

      • コンディションハンドラは、取扱対象コンディションの型指定子と、コンディションを引数とする関数から構成される。
      • コンディションハンドラは、コードのどこかで処理系に登録され、アクティブ状態になる。
      • コンディションハンドラ内関数で、該当コンディションを処理しないこともできる。その場合、処理系に制御は戻る。

    • 処理系は次のとおり。

      • コンディションが発生した場合、アクティブなコンディションハンドラのリストを探索して、その型に対応するコンディションハンドラを呼ぶ。
      • 同じ型に対するコンディションハンドラが複数ある場合は、スタック上の距離で、コンディション発生地点に近いものが呼ばれる。
      • 呼んだコンディションハンドラが処理を拒否した場合は、次のハンドラが存在すれば、それを呼ぶ。
      • コンディションハンドラを呼んだ時点ではスタックは巻き戻らない。処理の流れをどうするかはユーザが決めることだ。

    • handler-caseは、コンディションハンドラを作成し登録する。そして処理系は、conditionが発生した場合、スタックをコンディションハンドラ登録ポイントまで巻き戻し、コンディションハンドラを実行する。
    • ここの状況での定義。

      (defun parse-log-file (file)
      (with-open-file (in file :direction :input)
      (loop for text = (read-line in nil nil) while text
      for entry = (handler-case (parse-log-entry text)
      (malformed-log-entry-error () nil))
      when entry collect it)))

    • これはparse-log-fileとしては、やりすぎである。というのは、無視することを決めこんでいるからだ。不正なエントリがあったときにどうすべきかは、parse-log-fileを使う関数側で指定できるべきだろう。

  • 19.4 再起動

    • これを実現するには、parse-log-fileでは、condition発生時に実行可能なrestartの選択肢を登録するにかぎるようにする。
    • それにはrestart-caseを使う。
    • ここの状況での定義。

      (defun parse-log-file (file)
      (with-open-file (in file :direction :input)
      (loop for text = (read-line in nil nil) while text
      for entry = (restart-case (parse-log-entry text)
      (skip-log-entry () nil))
      when entry collect it)))

    • さて、ここで例として、parse-log-fileの上位に位置する(parse-log-fileを利用する)関数を2つ定義する。

      (defun log-analyzer ()
      (dolist (log (find-all-logs))
      (analyze-log log)))

      (defun analyze-log (log)
      (dolist (entry (parse-log-file log))
      (analyze-entry entry)))

    • これらの中で、malformed-...が発行された場合の対処を指定したい。handler-caseを使うと、そこまで巻き戻ってしまう。
    • そこで、handler-bindを使う。log-analyzerの中で定義する。

      (defun log-analyzer ()
      (handler-bind ((malformed-log-entry-error
      #'skip-log-entry))
      (dolist (log (find-all-logs))
      (analyze-log log))))

      (defun skip-log-entry (c)
      (let ((restart (find-restart 'skip-log-entry)))
      (when restart (invoke-restart restart))))


  • 19.5 複数の再起動を提供する

    • 最下層のparse-log-entryに、2つのrestartを導入する。

      (defun parse-log-entry (text)
      (if (woll-formed-log-entry-p text)
      (make-instance 'log-entry ...)
      (restart-case (error 'malformed-log-entry-error :text text)
      (use-value (value) value)
      (reparse-entry (fixed-text) (parse-log-entry fixed-text)))))

    • このうちのuse-valueを上位で指定して使うとしたら、例えば次のようだ。

      (defun log-analyzer ()
      (handler-bind ((malformed-log-entry-error
      #'(lambda (c)
      (use-value
      (make-instance 'malformed-log-entry :text (text c))))))
      (dolist (log (find-all-logs))
      (analyze-log log))))


  • 19.6 コンディションの別な使い道

    • errorとwarnとcerrorの差異。うーん。よくわからん。


自分なりに、こつこつ。

2009年1月13日火曜日

【実践CL】14 ファイルとファイルI/O

pareditの練習のため写経しながら。


  • 14.1 ファイルの読み込み
  • 14.2 バイナリデータの読み込み
  • 14.3 まとめ読み
  • 14.4 ファイル出力
  • 14.5 ファイルを閉じる

    • この5節、特になし。

  • 14.6 ファイル名

    • 論理パスネームを無視すれば、パスネームは悪いもんじゃないよ。
    • 論理パスネームには近づくなよ。
    • 名前文字列からパスネームへの対応はANSIでは規程されていないよ。

  • 14.7 パスネームでどうやってファイル名を表現するか
  • 14.8 新しいパスネームの構築
  • 14.9 ディレクトリ名の2つの表現方法

    • この3節、特になし。

  • 14.10 ファイルシステムとのやり取り

    • P系の言語の気安さとCLとの差は、この部分にあるのかもしれない。P系の言語はまずはUnixベッタリとして、ファイルシステムとのやりとり関係を扱いやすいように言語のconstructsが決められているような気がする。

  • 14.11 その他のI/O

    • 特になし。



こつこつ。

2009年1月11日日曜日

【実践CL】13 リストを越えて:コンスセルの別用途


  • 前説

    • 要旨:リストは幻想である。コンスセルから成るものをリストとして扱う関数群がある、というだけだ。
    • 要旨:同様に、コンスセルから成るものを違うものとした扱う関数群もある。木、集合、ルックアップテーブルだ。

  • 13.1 木


      ;; リストとして。
      (substitute 10 1 '(1 2 (3 2 1) ((1 1) (2 2))))
      ;; -> (10 2 (3 2 1) ((1 1) (2 2)))

      ;; 木として。
      (subst 10 1 '(1 2 (3 2 1) ((1 1) (2 2))))
      ;; -> (10 2 (3 2 10) ((10 10) (2 2)))

      なるほど。

  • 13.2 集合

    • 特になし。

  • 13.3 ルックアップテーブル:連想リストと属性リスト

    • あれ? '"a"の動作がわからない、、、。考える。

      • "a"であれば、これはまずreaderが文字列オブジェクトを生成する。それをevaluatorが評価する。評価した結果は同じ文字列オブジェクトである。それをprinterがR/W eqivalenceで印字する。それが"a"である。
      • '"a"の場合。分析の記述を簡単にするために、(quote "a")であるとする。これはまずreaderがLispフォームを生成するのだが、それはリストであり、第一要素はシンボルquoteである。第二要素は、文字列オブジェクトである。このリストをevaluatorが評価する。評価にあたり、quoteはスペシャルフォームであり、その引数位置にあるLispオブジェクトを評価せずにそのまま返却する。よって文字列オブジェクトである。それをprinterがR/W eqivalenceで印字する。それが"a"である。

    • ふむ。あたりまえのことだった。
    • getfは常にeqで比較。
    • 本のremfは例が悪い。次の例が簡明。

      CL-USER(32): *plist*
      NIL
      CL-USER(33): (setf (getf *plist* :a) 2)
      2
      CL-USER(34): (setf (getf *plist* :b) 3)
      3
      CL-USER(35): *plist*
      (:B 3 :A 2)
      CL-USER(38): (remf *plist* :a)
      T
      CL-USER(39): *plist*
      (:B 3)
      CL-USER(40):

    • get-propertiesも中途半端な例だな。簡明な例は次のとおり。

      CL-USER(47): *plist*
      (:C 0 :B 3 :A 2)
      CL-USER(48): (get-properties *plist* '(:a :b))
      :B
      3
      (:B 3 :A 2)
      CL-USER(49):


  • 13.4 DESTRUCTURING-BIND

    • 特になし。


こつこつ。

【実践CL】12 リスト処理:やつらがLISPと呼ぶ理由


  • 12.1 「リストなんてない」

    • そうだ、実践CLではrplaca,rplacdはつかわずにsetfでいくんだった。
    • 箱を使った説明は常にきらいだ。。。

  • 12.2 関数プログラミングとリスト

    • 要旨:リストは不変なオブジェクトでない。しかし、equalによって等価が判定されるとすれば、リストを入出力として関数プログラミングができる。

  • 12.3 「破壊的」な操作

    • 要旨:破壊的操作には二種類ある。副作用が目的なものと、リソースのリサイクルが目的のもの。
    • あれ、ここではnreverseのnはnon-consingのnになっている。どこかで、nuclearのnと読んだような。まあ、いいや。

  • 12.4 リサイクルな関数と構造共有の組み合わせ
    • 特になし。

  • 12.5 リスト操作関数

    • 特になし。

  • 12.6 マッピング

    • 特になし。


こつこつ。

2009年1月10日土曜日

【実践CL】11 コレクション


  • 前説

    • ANSIにコレクションという用語はあるのかな、Seaquencesというイメージがあるけど。調べる。HyperSpecにはなさそうだ。CLの用語としてではなく、プログラミング言語にまたがった一般的な概念として、ということなのだろう。

  • 11.1 ベクタ

    • elispではベクタはアトムだったが、CLでは?

      CL-USER(2): (vector 1)
      #(1)
      CL-USER(3): (atom (vector 1))
      T
      CL-USER(5): (atom (make-array 5 :fill-pointer 0))
      T
      CL-USER(8): (atom (make-array 5 :fill-pointer 0 :adjustable t))
      T
      CL-USER(9):

    • アトムだ!! adjustableなものもatomなのはちょっと驚いた。しかしsymbolも中身は書き換え可能だがatomだ。atomという概念は、中身の書き換え云々についてではなく、その表象というか表現というかなんというかについてのことなんだろう。

  • 11.2 特殊ベクタ

    • 特殊よりも特定とか特定化の方が訳としては好み。

  • 11.4 シーケンス反復関数

    • 特になし。

  • 11.5 さまざまな高階関数

    • 特になし。

  • 11.6 シーケンス全体の操作

    • 特になし。

  • 11.7 ソートとマージ

    • sortもstable-sotrも破壊的関数。

  • 11.8 部分シーケンス操作

    • 特になし。

  • 11.9 シーケンス述語

    • 特になし。

  • 11.10 シーケンスマッピング関数

    • ありmapcarは?と思い、HyperSpecを見ると、Sequencesのchapterにはmapとmap-intoしかない。調べるとConsesにあった。そうか、mapcarとかはconsesが対象だからね。
    • reduceの言葉のイメージが曖昧で、違和感がある。関数としての機能はわかるんだけど、なんでこれをreduceと呼ぶの? ということ。辞書を調べる。

      • reduce the speed. これは減ずる、という意味。なんか違う。
      • a beautiful building reduce to ashes. これはAをBにむりやり変える、ということ。ちょっと近いのかな。
      • reduce grapes to wine. これは分解する変形するということ。
      • これらを見てわかるとおりreduceにはより矮小な状態や要素的な状態に変えるというニュアンスがある。なので数学だと分数の訳文とか通分を指したりする。

    • うーん、やっぱりすっきりしない。

  • 11.11 ハッシュテーブル

    • 特になし。

  • 11.12 ハッシュテーブル上の反復

    • 特になし。


こつこつ。

2009年1月8日木曜日

【実践CL】10 数、文字、そして文字列


  • 10.1 数

    • 数について、CLは充実しているよ。

  • 10.2 数値リテラル

    • REPLにおける数値リテラルと数値オブジェクトとcanonical textual syntaxをちゃんと理解しとけよ。
    • 私の経験でいうと、baseとradixについて覚えるのがちょっと面倒。

  • 10.3 基本的な数学

    • 四則演算と、丸めを紹介。

  • 10.4 数値比較

    • 関数=は数として等価であるかを判断するよ。

  • 10.5 高度な数学

    • logとかsinとかいろいろな関数がCLにあるよ。

  • 10.6 文字

    • CLでは文字と数は違うよ。(Cとは違うということ)
    • 処理系内部で文字をどういうコーディングで扱うかはCLでは規程されていないよ。

  • 10.7 文字比較

    • 数値比較とは別に文字比較の関数があるよ。

  • 10.8 文字列

    • 文字列は、一次元の配列。要素は文字。

  • 10.9 文字列比較

    • 文字比較とは別に文字列比較の関数があるよ。


こつこつ。

2009年1月6日火曜日

【実践CL】9 実践:ユニットテストフレームワーク


  • この章の記述はすごいなぁ、と思う。おお、CLだとこういう風なプログラミングになるんだ、ということがありありと描写されている。
  • ここでは、このユニットテストフレームワークをどう使うか、使えるかという観点で整理する。

  • REPLの場合

    ;; システムのインストール
    (asdf:oos 'asdf:load-op :test-framework)

    ;; 名前のインポート
    (use-package :com.gigamonkeys.test)

    ;; テストを少し書く。仕様の記述にもなる。
    (deftest test-fact ()
    (check
    (= (fact 0) 1)
    (= (fact 1) 1)
    (= (fact 2) 2)
    (= (fact 5) 120)))

    ;; プロトタイプ関数を書く。
    (defun fact (n) 0)

    ;; テストにかける。
    (test-fact)
    FAIL ... (TEST-FACT): (= (FACT 0) 1)
    FAIL ... (TEST-FACT): (= (FACT 1) 1)
    FAIL ... (TEST-FACT): (= (FACT 2) 2)
    FAIL ... (TEST-FACT): (= (FACT 5) 120)
    NIL
    ;; テストをpassするように関数を書いていく。

    ;; さて別の関数を作る。

    ;; テストを書く。
    (deftest test-memberp ()
    (check
    (eql (memberp nil nil) nil)
    (eql (memberp '(nil) nil) t)
    (eql (memberp '(a) 'a) t)
    (eql (memberp nil 'a) nil)
    (eql (memberp '(b) 'a) nil)))

    ;; プロトタイプ関数を書いて、すべてのテストが通るまで作業、作業中もテストを足したりする。
    (defun memberp (x atom)
    (and (consp x)
    (not (null x))
    (if (atom (car x))
    (or (eql (car x) atom)
    (memberp (cdr x) atom))
    (or (memberp (car x) atom)
    (memberp (cdr x) atom)))))

    ;; 2つの関数のテスト達ができたので、まとめる。
    (deftest test-myfunc ()
    (com.gigamonkeys.test::combine-results
    (test-fact)
    (test-memberp)))
    ;; ここで、combine-resultsがexternalでないのがうざい。externalとして改変すべきかも。


  • ASDFを使っていないソースファイルの場合

    • cl-userで構築していくとする。
    • テストコードは本体ソース内に書くルールとする。
    • テストコードを完成版から削除する場合は、テスト用の式はすべて#+testというfeatureにする。featureのon/offは例えば次。

      (push :test *features*)
      (setf *features* (delete :test *features*))

    • 使い方の例はこんな感じ。

      (in-package :user)
      #+test
      (progn
      (print "test feature active")
      (require 'asdf)
      (asdf:oos 'asdf:load-op :test-framework)
      (use-package :com.gigamonkeys.test))

      ;;; =======================================

      (defun fact (n)
      (cond
      ((= n 0) 1)
      (t (* n (fact (1- n))))))

      #+test
      (deftest test-fact ()
      (check
      (= (fact 0) 1)
      (= (fact 1) 1)
      (= (fact 2) 2)
      (= (fact 5) 120)))

      (defun memberp (x atom)
      (and (consp x)
      (not (null x))
      (if (atom (car x))
      (or (eql (car x) atom)
      (memberp (cdr x) atom))
      (or (memberp (car x) atom)
      (memberp (cdr x) atom)))))

      #+test
      (deftest test-memberp ()
      (check
      (eql (memberp nil nil) nil)
      (eql (memberp '(nil) nil) t)
      (eql (memberp '(a) 'a) t)
      (eql (memberp nil 'a) nil)
      (eql (memberp '(b) 'a) nil)))

      ;;; =======================================

      #+test
      (deftest test-myfunc ()
      (com.gigamonkeys.test::combine-results
      (test-fact)
      (test-memberp)))
      #+test
      (test-myfunc)



  • このユニットテストフレームワークの鑑評

    • 方向性としてはルールベースプログラミング。
    • ただしインタプリタ方式ではなくコンパイラ方式。
    • CLの標準にないけどシンプルな構文構造についてマクロを書いて抽象化している。


こつこつ。

2009年1月4日日曜日

【実践CL】8 マクロ:自分で定義しよう


  • 8.1 マックはじめて物語

    • この寓話とてもいいよなぁ。寓話なんだけど、マクロの機構をありありと表現している。

  • 8.2 マクロ展開時 vs. 実行時

    • マクロってどこに格納されてたっけ? と思って調べてみると、シンボルのfunctionスロットだった。
    • 相互参照したマクロはどうなるのだろうとためしてみると。

      CL-USER(23): (defmacro hoge (var &rest body)
      `(piyo ,var (progn ,@body)))
      HOGE
      CL-USER(24): (defmacro piyo (var &rest body)
      `(hoge ,var (progn ,@body)))
      PIYO
      CL-USER(25): (macroexpand-1 '(hoge (x) (print x)))
      (PIYO (X) (PROGN (PRINT X)))
      T
      CL-USER(26): (macroexpand '(hoge (x) (print x)))
      16922048 bytes have been tenured, next gc will be global.
      See the documentation for variable *GLOBAL-GC-BEHAVIOR* for more information.

      16808512 bytes have been tenured, next gc will be global.
      See the documentation for variable *GLOBAL-GC-BEHAVIOR* for more information.
      16814144 bytes have been tenured, next gc will be global.
      See the documentation for variable *GLOBAL-GC-BEHAVIOR* for more information.
      Error: Received signal number 2 (Keyboard interrupt)
      [condition type: INTERRUPT-SIGNAL]

      Restart actions (select using :continue):
      0: continue computation
      1: Return to Top Level (an "abort" restart).
      2: Abort entirely from this (lisp) process.
      [1c] CL-USER(27): :reset
      CL-USER(28):

      うん。止まらない。

  • 8.3 DEFMACRO

    • 要旨:マクロを書くときの3ステップの紹介。

  • 8.4 試しにマクロを書いてみる:do-primes

    • 要旨:do-primesをまずは無邪気に書いてみる。

  • 8.5 マクロのパラメータ

    • 要旨:マクロのパラメータリストはdestructuring。

  • 8.6 展開形の生成

    • 要旨:バッククォート便利。

  • 8.7 漏れをふさぐ

    • 要旨:抽象化には漏れがある。(そりゃそうだ。具象から捨象するから抽象があるのだから。)
    • 要旨:マクロは「驚き最小の法則」で仕様を決めよ。
    • 要旨:漏れをふさぐには、評価順、評価回数、展開形内部変数はgensymの3つに注意。

  • 8.8 マクロを書くマクロ

    • 要旨:マクロを書くのを楽にするのにもマクロが使える。

  • 8.9 シンプルなマクロの先へ

    • 要旨:この章はタイピングを楽にする程度のマクロだった。次章ではマクロなしでは実現できないようなことをやる。


こつこつ。

2009年1月3日土曜日

【実践CL】7 マクロ:標準的な制御構文の構築


  • 前説

    • 要旨:プログラミングの大部分は言語の拡張である。CLのマクロは、関数、オブジェクトに並ぶ第三の拡張方法である。

  • 7.1 WHENとUNLESS

    • 要旨:マクロ機構が言語に組込まれているので、DSLを手軽に書ける。

  • 7.2 COND

    • 要旨:CONDの紹介。

  • 7.3 ANDとORとNOT

    • 要旨:ANDとORとNOTの紹介。(NOTは関数)

  • 7.4 繰り返し

    • 要旨:CLにおける繰り返し機構は階層をなしている。下から言うと、tagbodyとgo -> do -> dolist,dotimes,.. という系列と、loopがある。loopは英語のように繰り返しを書く機構。

  • 7.5 DOLISTとDOTIMES

    • 要旨:DOLISTとDOTIMESの紹介。

  • 7.6 DO

    • 要旨:DOの紹介。

  • 7.7 強力なLOOP

    • 感想:「LOOPを悪く言う人たちは、そのシンタックスがちっともLispっぽくない(つまり、括弧が足りない)と主張している」これは少なくともPGとNorvigについてはあてはまらない。彼らはどちらかというとLOOP否定派だが、その理由は、「拡張LOOPはANSI仕様において、またそれ以外のところにおいても、十分な構文定義が存在しない。そして実際、解釈が不定な表現も書けてしまう」ということがひとつ。あとは、「拡張loop構文は複数節の組み合わせという構造をもっているが、それをなす各節を拡張LOOP構文以外のところで再利用できないつくりはよろしくない」ということだったような。
    • 感想:私個人としては、プロトタイピングとかに有効につかって、固くするときにdoとかに書き換えればいいんじゃない、と考えている。
    • 要旨:賛否は別にして、こんなものもできちゃうのがマクロのパワーだ。


こつこつ。

2009年1月2日金曜日

【実践CL】6 変数

うーん。変数についてってちゃんと書いてある文章は少いんだよね。だから変数について読むときはちょっと気が重くなる。実践CLがどういう記述だったかは忘れちゃった。よい記述だといいなぁ。まあ、まったりまったり。坦々。


  • 前説

    • この説明はぼやっとしかわからない。これを尽きつめると、いろいろな言語を調べることになるので、それはやめておく。この後のCLについての具体的な説明を理解すればよしとする。

  • 6.1 変数の基礎

    • 「Common Lispの変数はC++やJavaのようには型付けされていないから、」ここの表現、間違ってはいないが微妙。type宣言すれば、変数に型を持たせることはできる。間違っていない、というのは「ようには」と書いてあるから。
    • お、変数の導入についての説明でdefunから入るのはいいかんじ。
    • 変数と、変数の名前を区別しているところがいいかんじ。

  • 6.2 レキシカル変数とクロージャ

    • 「Common Lispにおける束縛フォームが導入する変数は、すべてデフォルトではレキシカルなスコープを持つ。」progvを束縛フォームと呼ばないならなんだけど、束縛フォームの定義(P65)のところではprogvも含むような感じなのがあぶない。

      (defun bar (x)
      (format t "Parameter: ~a~%" x)
      (format t "symbol-value: ~a~%" (symbol-value 'x))
      (progv '(x) '(100)
      (format t "Parameter: ~a~%" x)
      (format t "symbol-value: ~a~%" (symbol-value 'x)))
      (format t "Parameter: ~a~%" x)
      (format t "symbol-value: ~a~%" (symbol-value 'x)))
      ;; 以下出力
      CL-USER(19): (bar 1)
      Parameter: 1
      symbol-value: 10
      Parameter: 1
      symbol-value: 100
      Parameter: 1
      symbol-value: 10
      NIL

    • なんでエクステントという概念を導入しないのかな? と思ったら、次節の脚注にあった。

  • 6.3 ダイナミック変数。またの名をスペシャル変数

    • ダイナミック変数、というとなんだかよくわからなくなるが、シンボルに値として入っているもので、その変数名について値を求められたときは、シンボルに入っている値を使いますよ、というのがスペシャル宣言。
    • ダイナミック変数の導入判断について、コードの上流下流とスタックの束縛の操作、というところはなにか本質的な気がする。このあたり、もっと尽きつめて考えてみなければいけない。というのは、プログラミングって「実行時のスタックの動き(動的)をイメージしつつ、それがよしなに動くようにソース(静的)を書く」ということのような気がしているから。これは気づきなのか誤解なのか。

  • 6.4 定数

    • defconstantはスペシャル。
    • +const+は、じゃなくて$consもありではというg000001さんの調査

  • 6.5 代入

    • ある変数について新しい値を設定するということ自体は、再度束縛する形でもできる。なので、変数について値を変えていくことと代入は別だと思う。
    • 代入は代入したいからするのだ。そして代入は、既存の束縛における値を変更することだ。
    • setqは使わずsetfのみ使うのがmodern。

  • 6.6 一般化代入

    • そうかsetfが多機能というだけではなくて、そもそもいろいろな言語がもっている=演算子?が多機能なんだ。

  • 6.7 場所の値を変更する別のやり方

    • rotatef、shiftf、忘れてた。。。便利だなぁ。


実践CL、悪くないなぁ。

さて、各プログラマの頭の中にある、プログラミング言語の意味論というのはかなり違うのではないか、と思えてきた。なぜかというと、自分ひとりだけを考えてみても、過去から今までの間いろいろ変遷してきているからだ。

そしてそれは、よりよいアプリケーションを書くという観点でいうと、ヒープとかスタックとかいうあたりのコンストラクトをどのように操作するかというところにあるのではないか(ここで言う意味論は学術的なもののことではなくプログラマがもつ内的イメージくらいのもの)。そういう意味でいうと、C言語はソースと内的イメージ(意味論)がかなり近いと思う。で、C言語はかなりシンプルな言語なので簡単であると。ただし、ハードウエアの進化によって意味論とハードウエアの距離は昔より開いている。CLの内的イメージ(意味論)はかなり複雑である。構文は簡単なんだけど、その背後にあるものが複雑。

そして残像のようにそういう内的イメージが言語に付きまとうのは、そもそも言語設計者がそういうイメージでモノを考えざるを得ないからじゃないか?

さらに言うと、プログラミングの理解がそういうものであるとして、そういもモノを変数は箱だとかなんだとか比喩だとか何だとかでわかったつもりにさせるような入門本をいくらやってもプログラミングなんてできるようにはならないんじゃないか??? それってある意味、「これをやってればあなたも英語がしゃべれます〜何も考えなくても楽にできるようになります〜」という触込みで、それを使って英語がしゃべれるようになった人が一人もいないような、詐欺教材がちまたにあふれているということじゃないか?

こつこつ。

2008年12月31日水曜日

【実践CL】5 関数


  • 前説

    • 「Lispの関数も、他の言語における関数と同じように、機能(functionality)を抽象化する基本的な仕組みを提供してくれるものだ。」加えて、データの抽象化という観点も重要に思える。

  • 5.1 新しい関数の定義

    • 要旨:defunの要素の一通りの説明。

  • 5.2 関数のパラメータリスト

    • 要旨:CLのパラメータリストは多機能。それによってプログラミングは随分楽になっている。
    • 要旨:常に入力が必要な変数は必須パラメータで書く。

  • 5.3 オプショナルパラメータ

    • 要旨:入力が必要じゃないときもある変数はオプショナルパラメータで書く。

  • 5.4 レストパラメータ

    • 要旨:可変個の入力を受け入れたいときはレストパラメータで書く。

  • 5.5 キーワードパラメータ

    • 要旨:パラメータが複数あって、入力時にそれらそれぞれを与えるかどうかが混沌としてる場合はキーワードパラメータで書く。

  • 5.6 異なる種類のパラメータの併用

    • 要旨:4種類使うなら、必須、オプショナル、レスト、キーワードの順。
    • 要旨:オプショナルとキーワードは同時に使うな。

  • 5.7 関数の戻り値

    • 要旨:defunが関数名でblockを用意してくれているので、return-from 関数名で関数の処理から脱出できる。

  • 5.8 データとしての関数または高階関数

    • 「関数をデータで扱える」というのはいくつかの意味を持っていると思う。まずファーストクラスとして扱えること、次に関数の記述自体がリストであること。

  • 5.9 無名関数

    • lambdaフォームは関数名の場所につかえるリストにすぎない。そして名前の変わりにその振舞を直接示している。
    • lambdaがマクロでもある、とHyperSpecにもあるが、これはちょっと理解しがたい。(lambda -> (function (lambda だとしたら、マクロ展開したときに無限ループになっちゃうのでは? CLtL1の解釈「funcallとかevalは、lambdaが冒頭のリストフォームを特別視する」でいいんじゃないかなぁ。
    • syntax sugar って構文糖でいいのかな? 構文糖衣が多数じゃないか?


前半は速めに進んで、後半の実践の章でまったりしたい。こつこつ。

2008年12月30日火曜日

【実践CL】4 シンタックスとセマンティックス


  • 4.1 何でこんなに括弧があるの?

    • M式の話。

  • 4.2 ブラックボックスをばらして中を見てみると

    • 「読取器は、どのようにして文字列がS式(s-expression)と呼ばれるLispのオブジェクトへと変換されるかを決める」これ、何か違和感があるな。まず、readerの重要要素はリーダーアルゴリズムとリードテーブルだろう。それらに従って文字列をLispオブジェクトに変換する。そうか、ここで言っているS式というのが何かというのがよくわからないのだ。そういえばS-expressionの正確な定義って何だ??
    • ちょっとしらべてみた。歴史的に言うと、マッカーシーがSymbolic expressionという用語を使っているようだ。ただし、ANSI CLにはS式という用語はないみたい。確かR5RSにもなかったはず。そして、S-expression自体は、Lispに閉じたものではなく汎用の表現形式として定義されているようだ。Rivest
    • なので、実践CLにおける、ここでのS式に対する言及は無視しておく。S式と言わずとも、Lispオブジェクト群という理解でいいのではないか。
    • readerが読む対象とする文字列は、リードテーブル次第で如何ようにもなりえる。なので、readerが読むものをS式ともいえない。また、CLのデフォルトであっても、例えば、'(a b)はS式ではないからそれをS式と呼ぶこともない。
    • ひとつ可能性があるのは、readerが読んだものをevalしないで印字形式に変換するとそれはS式なような気がする。すると、CLの実装として、readerがLispオブジェクトを生成するのではなく、その代わりにS式文字列を生成するようなものがあれば、そこではreaderがS式を生成すると言える。

  • 4.3 S式

    • 「数値は、そのまま数値だ」というのもわかりにくい。数値形式の文字列をreadすると、対応した数値のLispオブジェクトが生成される、ということだろう。

  • 4.4 LispフォームとしてのS式

    • ええっと、自己評価型オブジェクトの概念とR/W等価性とがごっちゃになっている。間違いなわけじゃないと思うが、今見返すと粗い説明だなぁ。

  • 4.5 関数呼び出し

    • 特になし。

  • 4.6 特殊オペレータ

    • quoteの説明のところもやはり不自然。「式を1つ取り、それをそのまま評価せずに返す」ではわかりにくいのでは? 「Lispオブジェクトを1つ取り、それをそのまま評価せずに返す」だろう。評価器への入力も出力もどちらも種別としてはLispオブジェクトのはずだ。そして、だからこそinとoutの間で「何もせずそのまま返す」ということが成り立つ。

  • 4.7 マクロ

    • (dolist (x foo) (print x))がマクロなのか関数なのかという不安について、xに着目せよ、と。callerがxを経由して値を与えるのではなく、xはこのフォームが指示する処理のなかで変数になっている、これは関数にはできなくて、マクロによってそういう処理に展開されるだろうという強い示唆だと。なるほど!

  • 4.8 真、偽、そして等しさ

    • 「いつでもEQLを使え」

  • 4.9 Lispコードの書式付け

    • C-cM-qがeliにはない。欲しいなぁ。


こつこつ。

2008年12月27日土曜日

【実践CL】3 実践:簡単なデータベース

PCLの今回の学習では写経はしない。gigamonkeysからソースをダウンロードして、必要に応じてそれをいじっていくことにする。そこで、環境整備。ASDFのサイトを念のため確認。以下メモ。

  • 念のため、(require 'asdf)。
  • ASDF:*central-registry*に#P"/Users/aka/local/lib/cl/systems/"などを登録。
  • systems以下にpracticals.asdのsymlinkを置く。practicals.asdがdependしている各章のasdもsystemsにsymlinkを置く。
  • (asdf:oos 'asdf:load-op :practicals)を実行。すると
    Error: component :CL-PPCRE not found, required by #
    [condition type: MISSING-DEPENDENCY]
    と文句を言われる。これ去年も言われたなぁ。
  • CL-PPCREを本家からDL。pclのソースと似たような感じでasdfを配置。
  • (asdf:oos 'asdf:load-op :practicals)。
    mp3-browserでduplicate? なerrorがでる。とりあえずskipして通した後、再度(asdf:oos 'asdf:load-op :practicals)すると文句はでない。まあいいや。
  • 今回は3章なので、(asdf:oos 'asdf:load-op :simple-database)でよし。
  • 3章のpackage.lispを見るとsymbolsをexternalにしていないので、(in-package :com.gigamonkeys.simple-db)でやる。

さて、実践CL。

  • 前説

    • 要旨:小さな実例を示す。記述にはごまかしもあるが、気にするな。

  • 3.1 CDとレコード
  • 3.2 CDのファイリング
  • 3.3 データベースの中身を見てみる
  • 3.4 ユーザインタラクションを改善する
  • 3.5 データベースの保存と読み出し

    • 感想:ここまでについて。最初のチュートリアルが入出力ごりごりなのが、比類ないところ。

  • 3.6 データベースにクエリを投げる

    • 感想:うむ。lambdaによって周囲の文脈から意味がかわる関数を書ける、というのはやっぱりすごいな。
    • 感想:そして、最初のチュートリアルで高階関数がでてくるのもめずらしいのでは。

  • 3.7 既存のレコードを更新する -- もう1つのWHEREの使い道
  • 3.8 ムダを排除して勝利を収める

    • 感想:で、マクロについても同様。


こつこつ。