Is this an implementation-specific behavior for li

2019-07-03 08:03发布

问题:

I'm testing out the code in this interesting answer.

CL-USER> (defun literal-cons ()
        (let ((cons '(1 . 2)))
          (incf (cdr cons))
          cons))
; in: DEFUN LITERAL-CONS
;     (INCF (CDR CONS))
; --> LET* 
; ==>
;   (SB-KERNEL:%RPLACD #:CONS1 #:NEW0)
; 
; caught WARNING:
;   Destructive function SB-KERNEL:%RPLACD called on constant data.
;   See also:
;     The ANSI Standard, Special Operator QUOTE
;     The ANSI Standard, Section 3.2.2.3
; 
; compilation unit finished
;   caught 1 WARNING condition
LITERAL-CONS
CL-USER> (literal-cons)
(1 . 3)
CL-USER> (literal-cons)
(1 . 3)
CL-USER> (literal-cons)
(1 . 3)

As the behavior is not the same, I am wondering if SBCL has used the mentioned warning to change the behavior to something it thinks is more likely expected from the user? Expected:

TEST> (defun literal-cons ()
        (let ((cons '(1 . 2)))
          (incf (cdr cons))
          cons))
LITERAL-CONS
TEST> (literal-cons)
(1 . 3)
TEST> (literal-cons)
(1 . 4)
TEST> (literal-cons)
(1 . 5)

回答1:

The short answer is that yes, this is implementation specific behavior. As discussed in Unexpected persistence of data,

The relevant text from the HyperSpec on quote is:

The consequences are undefined if literal objects (including quoted objects) are destructively modified.

This means that any behavior you see from such a function is implementation specific (even if certain behaviors are more common among implementations than others).



回答2:

You should use:

(let ((cons (cons 1 2)))
   (defun nonliteral-cons ()
       (incf (cdr cons))
       cons))