Lisp初体験-Plactical Common Lispノート-5.ミニデータベース-下


注意:もしあなたが初心者で、他の言語の基礎さえなければ、この編、すなわち<ミニデータベースの下>は、前の2編(上、中)の総括、最適化として、強いが、個人的な感覚は初心者を溝に連れて行く可能性が高い.so、読むには慎重にしなければならない.この編はスキップすることができる.
よし、上の赤い字が止められなかったら、始めましょう.
コードを簡潔にする
以前のデータベースも基本的に使用できましたが、whereのこの文のようなコード冗長性がたくさんあることがわかります.
(if title (equal (getf cd :title) title) t)

機能的には、すべての状況にマッチさせるために毎回多重判定(効率の無駄)をしなければならないが、コード的にはキーワードの違い以外に、まったく同じ型なのに、どうして同じ型でやらないのだろうか.
私たちの期待は、このように検索するなら:
(select (where :title "Give Us a Break" :ripped t))

実装されたコードは最終的にこのように見えます.

(select
 #'(lambda (cd)
     (and (equal (getf cd :title) "Give Us a Break")
          (equal (getf cd :ripped) t))))

提供されたものだけを判断する.
実はlispではこの目標を達成するのは簡単ですが、ここではlispの大殺器「マクロ」に触れなければなりません.以前は「共通関数として」と簡単に説明していましたが、事実はそうではありません.マクロはマクロ、関数は関数(少し回ります).しかしlispでは使い方が悪い.今のところ形を知るだけで、意味については、仁見智が見えます~
データベースから飛び出して、ここで簡単にマクロを建てて、使ってみます:
(defmacro backwards (expr) (reverse expr))

マクロと関数の定義キーワードは異なります.ここでreverseはマクロを持参し、次の役割を果たします.
(reverse '(1 2 3)) ==> (3 2 1)

私たちが書いたマクロを使ってください.
(backwards ("hello, world" t format))

結果:

hello, world
NIL

このマクロの使い方を理解しているかどうか、このマクロはlisp構文を逆方向にしています.同じ機能の関数を定義しようとすると、マクロの使い方に従ってエラーが表示されます(信じないでやってみてください)
データベースに戻ります.where文の冗長性が次のように短縮される場合は、次のようになります.
(equal (getf cd field) value)

前の欠陥を解決したようですが、試してみてください.

(defun make-comparison-expr (field value) 
  (list equal (list getf cd field) value))

何か問題があるようですが、修繕してください.

(defun make-comparison-expr (field value)
  (list 'equal (list 'getf 'cd field) value))

いくつかの単一引用符(')が多くなりました.これは、その後の東だけが実行されず、文字列として扱われることを意味します.試し:

*(make-comparison-expr :rating 10)
(EQUAL (GETF CD :RATING) 10)

結果はまたLisp文のようで、ここではlispの究極の奥義に関連しています:自分でコードを生産して実行します(従来のように、これは後の話です).
実装されたコードの一部を実装したい場合は、lispも考えています.

'(1 2 (+ 1 2))        ==> (1 2 (+ 1 2))
`(1 2 (+ 1 2))        ==> (1 2 (+ 1 2))
`(1 2 ,(+ 1 2))       ==> (1 2 3)

注意:最初の行のそれは単引用符(')で、次の2行は背引用符(`)で、キーボード位置の左上隅ESCボタンの下の位置で、その右側が感嘆符、1で、部分的にコードを実現したい場合は、実現部分の前にカンマをつければいいです.
次に、前の関数を変異します.

(defun make-comparison-expr (field value)
  `(equal (getf cd ,field) ,value))

外側に循環体を包む:

(defun make-comparisons-list (fields)
  (loop while fields
     collecting (make-comparison-expr (pop fields) (pop fields))))

これで、where関数をマクロにアップグレードできます.

(defmacro where (&rest clauses)
  `#'(lambda (cd) (and ,@(make-comparisons-list clauses))))

先に「,@」の組合せの用途を説明する:後の実行結果を上に組み込む

`(and ,(list 1 2 3))   ==> (AND (1 2 3))
`(and ,@(list 1 2 3))  ==> (AND 1 2 3)
`(and ,@(list 1 2 3) 4) ==> (AND 1 2 3 4)

ここでの「&rest」は「&key」と似ています.&keyは定義された「:abc」だけを受け入れます.&restは任意の入力を受け入れ、リストリストリストリストを構成します.たとえば、次のようになります.
(where :title "Give Us a Break" :ripped t)

パラメータは次のように整理されます.
(:title "Give Us a Break" :ripped t)

せっかく書いたものは、試してみるべきです.

* (select (where :title "Give Us a Break" :ripped t))
((:TITLE "Give Us a Break" :ARTIST "Limpopo" :RATING 10 :RIPPED T))

仕事はよくできているようで、コードは重複していません.最も重要なのは、cd/musicデータベースだけでなく、より高いレベルの抽象が適用範囲を大きく広げているようです.
ここでは、マクロと関数の違いがいくつかあります.マクロの抽象階層は関数よりも高く、ここのwhereのようにマクロがより一般的になります.
ミニデータベースは一段落しましたが、もちろん、ミニ版としては、まだ多くの欠陥があります.これは後の話があります.著者はついに彼がhelloがworldを終えた後にこのような章の動機を作ったことを認めた:hello worldは本当に小児科で、lispの牛Xを明らかにするのに十分ではない.これ~
(未完待機)