2012-01-19 38 views
31

Tôi tìm thấy một Similar question.Sự khác biệt giữa defvar, defparameter, setf và setq

Nhưng tôi hoàn toàn không hiểu giải thích đó.

Vì vậy, tôi đang cố gắng để chạy CLISP với ví dụ sau:

[1]> (defvar a 5) 
    A 
    [2]> (+ a 1) 
    6 
    [3]> (defparameter b 5) 
    B 
    [4]> (+ b 1) 
    6 
    [5]> (setf c 5) 
    5 
    [6]> (+ c 1) 
    6 
    [7]> (setq d 5) 
    5 
    [8]> (+ d 1) 
    6 
    [9]> (let ((a 500)) (+ a 1)) 
    501 
    [10]> (let ((b 500)) (+ b 1)) 
    501 
    [11]> (let ((c 500)) (+ c 1)) 
    501 
    [12]> (let ((d 500)) (+ d 1)) 
    501 
    [13]> 

Những gì tôi thấy là hoàn toàn giống nhau.

Tôi không thể tìm ra điều gì khác biệt với chúng?

Trả lời

55

DEFPARAMETER luôn gán giá trị. Vì vậy:

[1]> (defparameter a 1) 
A 
[2]> (defparameter a 2) 
A 
[3]> a 
2 

khi DEFVAR làm nó một lần duy nhất, vì vậy:

[4]> (defvar b 1) 
B 
[5]> (defvar b 2) 
B 
[6]> b 
1 

SETF là một macro trong đó sử dụng setq nội bộ, nhưng có khả năng nhiều hơn nữa. Theo cách đó, nó là một toán tử gán tổng quát hơn. Ví dụ. với SETF bạn có thể làm:

[19]> (defparameter c (list 1 2 3)) 
[21]> (setf (car c) 42)            
42 
[22]> c 
(42 2 3) 

nhưng bạn không thể làm điều đó với setq:

[23]> (setq (car c) 42)            
*** - SETQ: (CAR C) is not a symbol 
The following restarts are available: 
USE-VALUE  :R1  Input a value to be used instead. 
ABORT   :R2  Abort main loop 
Break 1 [24]> abort 
+0

Nếu một biến mà tôi xác định bằng defvar, tôi có thể thay đổi giá trị theo tham số không? Là cách chính xác để làm điều đó? Hoặc chỉ biến xác định trong tham số có thể được thay đổi bởi tham số? Cảm ơn bạn ~ – sam

+22

Cách đúng là sử dụng DEFVAR và DEFPARAMETER để khởi tạo giá trị trong các tệp, sử dụng một hoặc cái khác để khai báo các biến động trong trình lắng nghe và luôn sử dụng SETF để thay đổi giá trị trong mã không phức tạp. Sự khác biệt giữa DEFVAR và DEFPARAMETER sau đó trở thành "tôi có muốn đặt lại giá trị mỗi khi tôi tải tệp này," (sử dụng defparamete) "" hay không? " (sử dụng defvar). – Vatine

22

Cả hai defvardefparameter sẽ khai báo biến là "biến có phạm vi động". Ngoài ra, defparameter sẽ luôn đặt giá trị của biến thành giá trị bạn chuyển vào làm đối số thứ hai. Điều này khác với defvar, nó sẽ chỉ đặt giá trị của biến nếu trước đó chưa được đặt.

Xác định biến có setf hoặc setq trong phạm vi từ vựng toàn cầu không được xác định. Một số triển khai sẽ tạo ra một biến động phạm vi động cho bạn, một số sẽ không. Bạn có thể thấy thông báo chẩn đoán khi bạn làm điều đó lần đầu tiên.

Để hiểu sự khác biệt giữa các biến lexically-chỉnh phạm vi và tự động đặt phạm vi, hãy thử các đoạn mã sau:

* (defvar *a* 1) 

*A* 
* (let ((*a* 5)) (defun demo-a() *a*)) 

DEMO-A 
* (let ((b 5)) (defun demo-b() b)) 

DEMO-B 
* (let ((*a* 100)) (demo-a)) 

100 
* (let ((b 100)) (demo-b)) 

5 

Ở đây chúng ta tạo ra một biến động-chỉnh phạm vi và một hàm trả về giá trị (được định nghĩa bên trong một ràng buộc nơi nó có một giá trị khác nhau trong quá trình tạo hàm, điều này là không cần thiết và được thực hiện chỉ để trông giống như sự đóng cửa từ vựng trên b). Sau đó chúng ta định nghĩa một biến mới và định nghĩa một hàm trả về giá trị của nó.

Sau đó, chúng tôi gọi cả hai hàm, bên trong bao đóng ràng buộc một giá trị cho một biến cùng tên. Trong trường hợp phạm vi động, nó là cùng một biến. Trong trường hợp đóng cửa từ vựng (b), chúng chỉ có cùng tên, nhưng không phải là cùng một biến, vì chúng được định nghĩa trong hai loại đóng cửa từ vựng khác nhau.

Theo như sự khác biệt giữa setfsetq, cố gắng để luôn luôn sử dụng setf (Tôi không thể nghĩ ra bất kỳ ví dụ nơi (setq blah blahblah) sẽ làm việc và (setf blah blahblah) sẽ không làm điều tương tự).

+0

Bây giờ tôi biết sự khác biệt giữa defvar và defparameter. Nhưng khi nào thì chúng ta nên sử dụng setf hoặc setq? Cảm ơn bạn ~ – sam

+6

@sam: sử dụng 'defvar',' defparameter' hoặc 'let' để giới thiệu các biến mới. Sử dụng 'setf' và' setq' để thay đổi các biến hiện có.Sử dụng chúng để giới thiệu các biến mới là hành vi không xác định. –

+0

Ví dụ cuối cùng (let ((b 100)) (demo-b)) cho tôi 100 cũng, không 5 như được hiển thị –

Các vấn đề liên quan