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 |

2009-12-27

KMRCLを眺める (50) UPDATE-ALIST

| 00:48 | KMRCLを眺める (50) UPDATE-ALIST - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める (50) UPDATE-ALIST - わだばLisperになる

今回は、KMRCLのlists.lisp中からUPDATE-ALISTです。

とりあえず定義ですが、

(defmacro update-alist (akey value alist &key (test '#'eql) (key '#'identity))
  "Macro to support below (setf get-alist)"
  (let ((elem (gensym "ELEM-"))
        (val (gensym "VAL-")))
    `(let ((,elem (assoc ,akey ,alist :test ,test :key ,key))
           (,val ,value))
       (cond
        (,elem
         (setf (cdr ,elem) ,val))
        (,alist
         (setf (cdr (last ,alist)) (list (cons ,akey ,val))))
         (t
          (setf ,alist (list (cons ,akey ,val)))))
       ,alist)))

という風になっています。

マクロ展開した方が読みやすいので展開すると

(LET ((#:ELEM-2898 (ASSOC :Z *ALIST2* :TEST #'EQL :KEY #'IDENTITY))
      (#:VAL-2899 :BBBB))
  (COND (#:ELEM-2898 (SETF (CDR #:ELEM-2898) #:VAL-2899))
        (*ALIST2* (SETF (CDR (LAST *ALIST2*)) (LIST (CONS :Z #:VAL-2899))))
        (T (SETF *ALIST2* (LIST (CONS :Z #:VAL-2899)))))
  *ALIST2*)

となります。

指定したキーで該当する要素があれば、指定した値に更新。

なければ(key . val)を最後に追加

alistが空なら((key . val))というalistを作成

というところでしょうか。

(DEFVAR *ALIST* (LIST (CONS :A :B) (CONS :C :D) (CONS :E :F)))
(DEFVAR *ALIST2* (COPY-ALIST *ALIST*))
(DEFVAR *ALIST3* () )

*ALIST*
;⇒ ((:A . :B) (:C . :D) (:E . :F))

(UPDATE-ALIST :A :BBBB *ALIST*)
;⇒ ((:A . :BBBB) (:C . :D) (:E . :F))

*ALIST2*
;⇒ ((:A . :B) (:C . :D) (:E . :F))

(UPDATE-ALIST :Z :BBBB *ALIST2*)
;⇒ ((:A . :B) (:C . :D) (:E . :F) (:Z . :BBBB))

*ALIST3*
;⇒ NIL

(UPDATE-ALIST :Z :BBBB *ALIST3*)
;⇒ ((:Z . :BBBB))

しかしこれマクロじゃなくて関数で良いような気がするんですが…。

(DEFUN UPDATE-ALIST-FN (AKEY VALUE ALIST &KEY (TEST #'EQL) (KEY #'IDENTITY))
  (LET ((ELEM (ASSOC AKEY ALIST :TEST TEST :KEY KEY))
        (VAL VALUE))
    (COND (ELEM (SETF (CDR ELEM) VAL))
          (ALIST (SETF (CDR (LAST ALIST)) (LIST (CONS AKEY VAL))))
          (T (SETF ALIST (LIST (CONS AKEY VAL)))))
    ALIST))

ゲスト



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