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 |

2008-07-18

CLで学ぶ「プログラミングGauche」 (9.1)

| 00:05 | CLで学ぶ「プログラミングGauche」 (9.1) - わだばLisperになる を含むブックマーク はてなブックマーク - CLで学ぶ「プログラミングGauche」 (9.1) - わだばLisperになる

「プログラミングGauche」をCLで演習してみていましたが、2ヶ月も放置してしまいました。

どうも一回の内容を長くしてしまうと億劫になってしまうようなので、細切れに行くことに方針変更しました。

9.1 集合

このセクションで登場するmemberですが、CLでは、memberは、比較の為の関数を:testで指定できるので、srfi-1拡張相当です。

デフォルトでは、eqlが比較に使われます。

また、keyが取れて、

member
(member 'bar '((foo) (bar) () (baz)) :key #'car)
;=> ((BAR) NIL (BAZ))

のようなこともできます。

(defparameter *inventory* '(cookie dagger))

(member 'cookie *inventory* :test #'equal)

(defun has-item? (item)
  (member item *inventory*))
delete

srfi-1のdeleteに相当するものは、CLでは、removeになります。

また、同じ機能で引数リストを破壊的に変更するものにdeleteがあります。

(remove 1 '(1 2 1 2 1 2 1 2))
;=> (2 2 2 2)

itemを取り除く上限の個数も標準で指定できます。

(remove 1 '(1 2 1 2 1 2 1 2) :count 1)

;=> (2 1 2 1 2 1 2)

[練習問題]

CLのremoveは、この問題のように全く削除要素がみつからなかった場合に、与えられた引数をそのまま返しても良いということになっています。

CLHS: Function REMOVE, REMOVE-IF, REMOVE-IF-NOT...

逆にいえば、この仕様だとremoveの結果を破壊することの安全が保証されていないので破壊する場合は、リストをコピーしてやる必要があります。

(defun delete-1 (item lst test)
  (if (endp lst)
      ()
      (let ((tail (delete-1 item (cdr lst) test)))
        (if (funcall test item (car lst))
            tail
            (if (eq (cdr lst) tail)
                lst
                (cons (car lst) tail))))))

(let ((data (list 1 2 3 4 5)))
  (eq data (delete-1 0 data #'equal)))
;=> T
代入

Gaucheのset!に相当するものは、setfか、setqになります。

また、Schemeの命名規則では、名前の最後に!が付くと破壊的操作となりますが、CLの場合、CL以前のLISPの色々な命名規則が混っていますので、いまいち統一感に欠けます。

nconc、nreverse等、nが付いたり、remove系に対してのdelete系というのが主なところです。