Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-12-14

Practical Common Lisp (6)

| 17:35 | Practical Common Lisp (6) - わだばLisperになる を含むブックマーク はてなブックマーク - Practical Common Lisp (6) - わだばLisperになる

引き続きPractical Common Lisp 第三章3. Practical: A Simple Databaseを読んでみています。一日1段落のペースになりつつあります…。

Querying the Database

とりあえず出てきたコードを暗記して再現して感想をメモ
(select :artist "Dixie Chicks")

とりあえず、こういう関数を作って検索することにしたのだろう。

(defun select-by-artist (artist)
  (remove-if-not (lambda (cd) (equal (getf cd :artist) artist))
		 *db*))

できた。アーティスト名を引数にとって検索するものの様子。

Practical Common Lispでは、lambdaにはfunction(#')を付ける派のようです。

(defun select (selector-fn)
  (remove-if-not selector-fn *db*))

できた。これはなんだろう高階関数化するんだろうか。

(defun artist-selector (artist)
  (lambda (cd) (equal (getf cd :artist) artist)))

無名関数に名前を付けるらしい。

(select (artist-selector "Aldo Ciccolini"))

のように使うらしい。でもなんとなく無理矢理な気が。

(defun where (&key artist title rating (ripped nil ripped-p))
  (lambda (cd)
    (or 	
     (if artist (equal (getf cd :artist) artist))
     (if title (equal (getf cd :title) title))
     (if rating (equal (getf cd :rating) rating))
     (if ripped-p (equal (getf cd :ripped) ripped)))))

間違えた。動きは同じだけど、andと、デフォルト値tの組み合わせで

(defun where (&key artist title rating (ripped nil ripped-p))
  (lambda (cd)
    (and
     (if artist (equal (getf cd :artist) artist) t)
     (if title (equal (getf cd :title) title) t)
     (if rating (equal (getf cd :rating) rating) t)
     (if ripped-p (equal (getf cd :ripped) ripped) t))))

だった。

自分には、

(or (if pred t nil)
    (if pred t nil))

の方が

(and (if pred nil t)
     (if pred nil t))

より自然に感じるな。

とりあえず、一般化されたwhereという関数を作って、selectに渡すらしい。関数型言語っぽい。

以上を踏まえて本文を読んでみる

(select :artist "Dixie Chicks")という感じで検索できるようにしたい。

  • REMOVE-IF-NOTの説明
    • リストから条件に合わないものを削除して、結果のリストを返す。結果として欲しいもののリストが返る。
    • REMOVE-IF-NOTには関数を渡す。LAMBDAで作った無名関数も渡せる。
  • LAMBDAの説明。
    • 無名関数を作る。名前がないことを除いては、DEFUNの様なもの。
  • 以上を踏まえて、select-by-artistを作ってみる。
  • 同じ流れでselect-by-title, select-by-rating, select-by-title-and-artistと作っても良いが、もう少し一般化して、selectという関数を引数に取るより一般化された関数を作ってみる。
  • selectの中の変数名に#'は付けなくて良いのかという疑問→いりません
  • selectに渡す関数をもっと一般化してみる
    • キーワードパラメータの説明
(defun foo (&key a b c) (list a b c))

(foo :a 1 :b 2 :c 3)  ==> (1 2 3)
(foo :c 3 :b 2 :a 1)  ==> (1 2 3)
(foo :a 1 :c 3)       ==> (1 NIL 3)
(foo)                 ==> (NIL NIL NIL)

という風に、キーワードと値のペアを便利に渡す仕組みがCommon Lispにはあるので、これを利用する。

      • 特徴
        • キーワード:値というペアで値が特定できるので、関数呼び出しの時に、引数のペアの順番は任意にできる。
        • 関数呼び出しの時に、引数のペアを与えなければ、定義時に設定したデフォルト値が渡される
        • デフォルト値設定について
(defun foo (&key a (b 20) (c 30 c-p)) (list a b c c-p))

という風に指定できる。

aは指定していないが、指定していない場合、デフォルト値としてNILが設定される。

bは、デフォルト値は20

cは、デフォルト値は30で、更に、値が指定されているかどうかを判定する機構も使っている。

この場合、c-pという変数に、tかnilが渡る。

  • 以上を踏まえて、SQLっぽく、whereという関数を定義することによって、
(select (where :artist "Dixie Chicks"))

という風に使えるようにしてみる。

  • where関数の定義と説明
    • ifの中で、ripped-pを判定しているのは、
(if ripped (equal (getf cd :ripped) ripped) t)

では、rippedの真偽を確かめたいのか、それとも引数の指定がないのでデフォルト値でnilが渡ってきたのが区別できないため。ripped-pで調べる必要がある。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20071214