標準組み込みのシンボルを上書きしたい - lisp-cookbook-ja/common-lisp GitHub Wiki

基本的に標準組み込みのシンボルを上書きすることはLisp処理系を破壊することにも繋がるため、何が起きるかが完全に予期できない場合には避けましょう。

下記に、間接的に標準組み込みのシンボルを上書きすることとほぼ同義になる良くある事例を挙げます。

tを変数名に使いたい

t(cl:t)は真値を代表するシンボルであり定数です。

tは定数のため代入や束縛をすることはできません。

(let ((t 42))
  t)
;>>> Cannot bind "it is a constant" -- t.

何らかの理由で、Tという変数名が多用される場合、別途パッケージを作成し、そのパッケージ内では、cl:t を t という名前で使わないようにすれば問題ありません。

下記では、tcl::t というシンボルが、tclパッケージ内では、tとして表記されます。

(defpackage tcl 
  (:use cl)
  (:shadow T))

(in-package tcl)

(let ((t 42))
  t)
;=> 42 

+ を総称関数として拡張したい

上記 t と同様に、cl:+ は組み込み関数であり上書きは避けるべきです。~%

(defpackage gcl
  (:use cl)
  (:shadow +))

(in-package gcl)

(defgeneric + (x y))

(defmethod + ((x number) (y number))
  (cl:+ x y))

(defmethod + ((x list) (y list))
  (concatenate 'list x y))

(defmethod + ((x string) (y string))
  (concatenate 'string x y))

(+ 0 1)
;=> 1 

(+ "0" "1")
;=> "01" 

(+ '() '(()))
;=> (nil) 

発展した話題

上記のようにして、組み込み標準の関数名と同じsymbol-name(≠同じシンボル)でライブラリ等を作成し、シンボルをエクスポートした場合、標準のcommon-lisp(cl)パッケージと一緒にuse-packageする際には使う側が常にsymbol-nameの競合を処理しなければなりません。~%

このような不便を排除するために、標準のcommon-lispパッケージの代わりとするベースパッケージや、common-lisp-userパッケージのような作業用パッケージも提供することがあります。

身近な例では、closer-mopのc2cl、c2cl-userパッケージ等があります。