あどけない話

インターネットに関する技術的な話など

On Lisp

以前から、Lisp でのデザインパターンとは何かについて考えていました。それに答えを与えてくれそうな 「On Lisp」 という本を読んでいます。

On Lisp

On Lisp

quote の副作用

長年 Lisper をやってきたのに、quote で作られたリストを返す関数に副作用があることを、恥ずかしながらこの本で初めて知りました。

たとえば、以下のような関数です。

(defun foo(expr)
  (append expr '(a b)))

実行してみましょう。

(foo '(1 2 3))
;; => (1 2 3 a b)

さてここで、foo の返り値に破壊的な関数 nconc を使ってみます。

(nconc (foo '(1 2 3)) '(c))
;; => (1 2 3 a b c)

すると、挙動が変わります。

(foo '(1 2 3))
;; => (1 2 3 a b c)

がーん。

quote で作られるリストは静的だからですね。解決するには、リストを list で動的に作ればいいそうです。

(defun bar(expr)
  (append expr (list 'a 'b)))

(bar '(1 2 3))
;; => (1 2 3 a b)

(nconc (bar '(1 2 3)) '(c))
;; => (1 2 3 a b c)

(bar '(1 2 3))
;; => (1 2 3 a b)

勉強になるなぁ。

back quote

少なくとも Emacs Lisp では、"," や ",@" を使わない back quote は quote に等価のようです。

(defun foo(expr)
  (append expr `(a b)))

(foo '(1 2 3))
;; => (1 2 3 a b)

(nconc (foo '(1 2 3)) '(c))
;; => (1 2 3 a b c)

(foo '(1 2 3))
;; => (1 2 3 a b c)

"," や ",@" を使うと、リストが動的に作られるようです。

(defun bar(expr)
  `(,@expr a b))

(bar '(1 2 3))
;; => (1 2 3 a b)

(nconc (bar '(1 2 3)) '(c))
;; => (1 2 3 a b c)

(bar '(1 2 3))
;; = (1 2 3 a b)