2016-12-26 6 views
7

は(Reddit /r/lisp questionから)このコード例を考える:SBCLは、ローカルバインドされた関数オブジェクトのEQnessを、設定されていなくても変更しますか?

(defun next (pos) 
    (nth (1+ pos) 
     '(0 1 2 3 4 5 6 7 8 9 10))) 

(defvar *next* (function next)) 

(let ((old-next #'next) 
     (previous (make-hash-table))) 
    (format t "~% 1 EQ? ~a" (eq old-next *next*)) 
    (defun next (pos) 
    (or (gethash pos previous) 
     (setf (gethash pos previous) (funcall old-next pos)))) 
    (format t "~% 2 EQ? ~a" (eq old-next *next*))) 

は、上記機能NEXTを確立します。 LETの内部では、古い機能をOLD-NEXTに保存しています。次に、グローバル関数NEXTLETの中に再定義します。

CCL/CMUCL/GCL/ECL/CLISP/LispWorks/ABCL:

* (load "test.lisp") 

1 EQ? T 
2 EQ? NIL 

ローカルの値:

? (load "test.lisp") 

1 EQ? T 
2 EQ? T 

のみSBCL(1.3.11 SBCL)は、異なる結果を有します変数old-nextは、グローバル変数*next*の値に対して、eqでなくなりました。

なぜですか?

+0

SBCLのメーリングリストでもお聞きしましたか? – coredump

+0

@coredump:いいえ、まだ –

答えて

2

SBCLがスマートにしようとしていて、変数を最適化するように見えます。

(defun foobar() 
    (print :foo)) 

(let ((old #'foobar)) 
    (funcall old) 
    (defun foobar() 
    (print :bar)) 
    (funcall old)) 

プリント

:FOO 
:BAR 

しかし、あなたが変数にSETFを使用する場合、

(defun foobar() 
    (print :foo)) 

(let ((old #'foobar)) 
    (funcall old) 
    (setf old #'foobar) 
    (defun foobar() 
    (print :bar)) 
    (funcall old)) 

それは

:FOO 
:FOO 
2

を出力動作は、変数は特別なものかどうかを変更します。

(inspect 
    (progn 
    (defun next()) 
    (let ((old #'next) 
      (foo #'next)) 
     (declare (special foo)) 
     (defun next() :different) 
     (list old foo)))) 

The object is a proper list of length 2. 
0. 0: #<FUNCTION NEXT> 
1. 1: #<FUNCTION NEXT {10037694EB}> 

最初の要素は、最新の定義を参照し、特殊変数から取得した2番目の要素は、予期したとおりに古い定義です。 特別な宣言を削除すると、両方の参照がEQになり(新しい定義をポイントします)。

関連する問題