2013-06-18 17 views
5

Hướng dẫn về phong cách Lisp chung của Google nói Avoid modifying local variables, try rebinding insteadTừ Hướng dẫn về phong cách chung của Google: "Tránh thay đổi các biến cục bộ, hãy thử khôi phục" thay vì "nghĩa là gì?

Điều đó có nghĩa là gì? Việc rebinding có nghĩa gì trong câu đó?

+1

Rebinding, rất có thể, như trong mặt nạ tên trước đó với cái mới, ví dụ, '(let ((1)) (let ((a 2)) ...))' –

+1

Đây là một hướng dẫn câm . Đi đầu và sửa đổi tất cả các biến cục bộ mà bạn muốn. Lưu ý rằng 'loop' sửa đổi các biến cục bộ. Trong '(vòng lặp cho i dưới 10 ...)', việc trả lại 'i' không xảy ra; một trường hợp duy nhất của 'i' được bước, do đó," tránh sửa đổi các biến cục bộ "là tương đương với" tránh 'vòng lặp'". Và do đó, theo quy tắc suy luận "reductio ad religio", chúng tôi chứng minh hướng dẫn này sai. – Kaz

+0

Như bạn có thể đã biết, tiêu chuẩn Common Lisp không xác định có hay không 'LOOP' ràng buộc một biến mới hoặc thay đổi biến hiện tại. Và tôi hiểu điều này như một hướng dẫn chung, chứ không phải là một quy tắc nghiêm ngặt mà không bị phá vỡ. –

Trả lời

9

Nó có nghĩa là bạn nên tạo biến mới thay vì thay đổi giá trị của những cái cũ. Ví dụ, chúng ta hãy đoạn mã sau:

(defun foo (x) 
    (when (minusp x) 
    (setq x (- x))) 
    do something with x) 

Thay vào đó, ta nên tạo một ràng buộc mới và sử dụng rằng một thay vì:

(defun foo (x) 
    (let ((xabs (if (minusp x) 
        (- x) 
        x))) 
    do something with xabs) 

Lý do cho điều này là bạn sẽ luôn luôn biết những gì một biến chứa, vì nó sẽ không bao giờ thay đổi. Nếu bạn muốn giá trị mới, chỉ cần sử dụng biến chứa giá trị mới đó.

Bây giờ bạn có thể hỏi tại sao điều này lại quan trọng như vậy? Vâng, một số người có sở thích mạnh mẽ hơn so với những người khác. Đặc biệt những người thích nhấn mạnh khía cạnh chức năng của Lisp sẽ ủng hộ phong cách này. Tuy nhiên, bất kể sở thích, nó có thể rất hữu ích để luôn luôn có thể dựa vào thực tế là các biến không thay đổi. Dưới đây là một ví dụ nơi này có thể quan trọng:

(defun foo (x) 
    (let ((function #'(lambda() (format t "the value of x is ~a~%" x)))) 
    (when (minusp x) 
     (setq x (- x))) 
    (other-function x) 
    function)) 

Sau đó, giá trị trả về của FOO là một chức năng mà khi được gọi với in giá trị của x. Tuy nhiên, giá trị sẽ là x sau đó trong hàm, giá trị tuyệt đối. Điều này có thể rất đáng ngạc nhiên nếu hàm này lớn và phức tạp.

+0

+1. Thật thú vị khi lưu ý rằng '(let ((x (abs x))) ...)' cũng sẽ hoạt động - không quá nhiều hàm 'abs', nhưng thực tế là cùng một tên biến có thể được sử dụng cho biến mới. –

+3

Việc đóng cửa đề cập đến một giá trị sửa đổi nhắc tôi về cách sử dụng JavaScript, sử dụng vòng lặp for để lặp qua một loạt các nút và gắn các trình xử lý onclick tham chiếu đến một chỉ mục lặp lại là một ý tưởng không tốt –

+3

@LeCurious. -vấn đề biến đổi xuất hiện trong Common Lisp, đặc biệt với [macro loop] (http://www.lispworks.com/documentation/HyperSpec/Body/m_loop.htm). Ví dụ, xem [hành vi bất ngờ với macro và đóng vòng lặp] (http://stackoverflow.com/questions/15714537/unexpected-behavior-with-loop-macro-and-closures), thể hiện hành vi chính xác này. –

4

Tôi không biết Lisp thường đủ để trả lời bằng cách thực hiện điều này trong Common Lisp, vì vậy tôi đang sử dụng Scheme cho ví dụ dưới đây. Giả sử bạn đang viết một hàm để trả lại giai thừa của một số. Dưới đây là một cách tiếp cận "sửa đổi các biến địa phương" để chức năng đó (bạn sẽ phải xác định riêng của bạn while vĩ mô, nhưng nó không phải là khó khăn):

(define (factorial n) 
    (define result 1) 
    (while (> n 0) 
    (set! result (* result n)) 
    (set! n (- n 1))) 
    result) 

Dưới đây là một cách tiếp cận "rebind biến địa phương" để chức năng đó:

(define (factorial n) 
    (let loop ((n n) 
      (result 1)) 
    (if (zero? n) 
     result 
     (loop (- n 1) (* result n))))) 

Trong trường hợp này, loop được gọi với giá trị mới để rebind với mỗi lần. Các chức năng tương tự có thể được viết bằng cách sử dụng do vĩ mô (trong đó, bằng cách này, cũng sử dụng rebinding, không thay đổi, ít nhất là trong Scheme):

(define (factorial n) 
    (do ((n n (- n 1)) 
     (result 1 (* result n))) 
     ((zero? n) result)))