3

このコードを考慮すると:

(defclass test () ((test :initform nil :accessor test)))
#<STANDARD-CLASS TEST>
(defvar *test* (make-instance 'test))
*TEST*

そしてこのテスト:

(funcall #'test *test*)
nil

これが機能すると予想されます:

(setf (funcall #'test *test*) 123)

と同じ

(setf (test *test*) 123)
123

しかし、次のようになります。

; in: LAMBDA NIL
;     (FUNCALL #'(SETF FUNCALL) #:NEW1175 #:TMP1177 #:TMP1176)
; ==>
;   (SB-C::%FUNCALL #'(SETF FUNCALL) #:NEW1175 #:TMP1177 #:TMP1176)
; 
; caught WARNING:
;   The function (SETF FUNCALL) is undefined, and its name is reserved by ANSI CL
;   so that even if it were defined later, the code doing so would not be portable.
; 
; compilation unit finished
;   Undefined function:
;     (SETF FUNCALL)
;   caught 1 WARNING condition

なぜ機能しないのですか?どうすれば回避できますか?

SBCL と CLISP のいずれかを使用してテストしましたが、結果は同じでした。

4

2 に答える 2

6

SETFは特別な形式です (それを説明する仕様の部分については、http://www.lispworks.com/documentation/HyperSpec/Body/05_aa.htmを参照してください)。2 番目の例は、lisp の実装が(test *test*)構文的に解釈されるため機能します。

何が起こっているかを確認するには、次のセッションをご覧ください。

This is SBCL 1.0.56.0.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (defclass test () ((test :initform nil :accessor test)))

#<STANDARD-CLASS TEST>
* (defvar *test* (make-instance 'test))

*TEST*
* (macroexpand '(setf (test *test*) 123))

(LET* ((#:*TEST*606 *TEST*))
  (MULTIPLE-VALUE-BIND (#:NEW605)
      123
    (FUNCALL #'(SETF TEST) #:NEW605 #:*TEST*606)))
T
* #'(setf test)

#<STANDARD-GENERIC-FUNCTION (SETF TEST) (1)>
* (macroexpand '(setf (funcall #'test *test*) 123))

(LET* ((#:G609 #'TEST) (#:*TEST*608 *TEST*))
  (MULTIPLE-VALUE-BIND (#:NEW607)
      123
    (FUNCALL #'(SETF FUNCALL) #:NEW607 #:G609 #:*TEST*608)))
T

最初のマクロ展開は、呼び出し#'(setf test)によって自動的に定義されるライター関数である を取得することに注意してください。defclass2 番目はやみくもに に変換されますが#'(setf funcall)、これは存在しません (したがって、エラーが発生します)。

あなたの「どうすれば回避できますか?」に答えるために。質問、おそらくあなたが何をしようとしているのかについてもっと知る必要があるでしょう. たとえば、(setf (slot-value object slot-name))プログラムでスロットを選択できるようなものを使用できます。

于 2012-05-28T14:39:54.923 に答える
2

slot オプションは、スロット値の読み取りとスロット値の設定という 2 つの関数を定義:accessorします。Common Lisp の後者の場合、関数名はシンボルではなくリストであることに注意してください。FOO(SETF FOO)

関数と値のリスト (コメント) が必要な場合は、リストにセッター関数を含める必要があります。

(defclass test ()
 ((foo :initform nil :accessor foo)
  (bar :initform nil :accessor bar)))

(map nil
     (lambda (function argument)
       (funcall function argument object))
     (list #'(setf foo) #'(setf bar))
     (list arg1 arg2))
于 2012-05-28T19:15:02.263 に答える