by shigemk2

当面は技術的なことしか書かない

リスト遊び 8-6 連結!

前回
リスト遊び 8-5 置換! - by shigemk2

副作用のある連結nconc
2つのリストを連結する。
最初のリストの最後のセルのCDRを
次のリストに指名する関数である。

(setq zoo '(1 2))
(1 2)
(setq goo '(3))
(3)
(nconc zoo goo)
(1 2 3)
zoo
(1 2 3)

副作用のない連結append
最初のリストのコピーの、最後のセルのCDRを
次のリストに指名する関数である。
出来あがったものは、コピー。

(setq zoo '(1 2))
(1 2)
(setq goo '(3))
(3)
(append zoo goo)
(1 2 3)
zoo
(1 2)

どちらも、引数にnilが含まれているときは、例外的な動作をする。
第一引数がnilなら第二引数を、第二引数がnilなら第一引数を返す。
この動作により、nconcが不具合を起こすときがある。

(setq zoo nil)
nil
(setq goo '(3))
(3)
(nconc zoo goo)
(3)
zoo ;; '(3)みたいなのを期待していたのに、
nil ;; nilのままだよ

;; setqと組み合わせるとよいです。
(setq zoo nil)
nil
(setq goo '(3))
(3)
(setq zoo (nconc zoo goo))
(3) ;; まあこれだとガベージコレクションが起こるわけだが

lst1の最後のセルに、lst2が指しているセルを参照させればよいので、
以下のように実装できるよ。

(defun nconc (lst1 lst2)
  (cond
   ((null lst1) lst2)
   ((null lst2) lst1)
   (t
    (let ((ptr lst1))
      (while (cdr ptr)
      	(setq ptr (cdr ptr)))
      (setcdr ptr lst2))
    lst1)))
nconc
(nconc '(1 2 3) '(4 5 6))
(1 2 3 4 5 6)

(defun append (lst1 lst2)
  (cond
   ((null lst1) lst2)
   ((null lst2) lst1)
   (t
    (let ((ret (copy-list lst1))
	  ptr)
      (setq ptr ret)
      (while (cdr ptr)
	(setq ptr (cdr ptr)))
      (setcdr ptr lst2)
      ret))))
append
(setq zoo '(1 2 3))
(1 2 3)
(setq goo '(4 5 6))
(4 5 6)
(append zoo goo)
(1 2 3 4 5 6)
zoo
(1 2 3)

リスト遊び―Emacsで学ぶLispの世界 (ASCII SOFTWARE SCIENCE Language)

リスト遊び―Emacsで学ぶLispの世界 (ASCII SOFTWARE SCIENCE Language)