2009-11-21 33 views
16

Mặc dù tôi đã sử dụng Clojure, tôi đã không xem xét các quy tắc phạm vi chi tiết. Tôi đang bối rối hơn khi đọc tài liệu. Tôi đã thực hiện một thử nghiệm nhỏ để thử các giải pháp phạm vi và bị trì hoãn trước sự phức tạp. Ai đó có thể giải thích ý định và các quy tắc khác nhau mà Clojure sử dụng không?Quy tắc phạm vi trong Clojure

(def x 1) 

(defn dummy-fn2[] 
    (+ x 1))   

(defn dummy-fn[] 
    (println "entering function: " x) 
     (let [x 100] 
     (println "after let: " x) 
     (let [x (dummy-fn2)] 
      (println "after let and dummy2: " x) 
      (binding [x 100] 
      (println "after binding: " x) 
      (let [x (dummy-fn2)] 
       (println "after binding and dummy2: " x)))))) 

1:2 foo=> (dummy-fn) 
entering function: 1 
after let: 100 
after let and dummy2: 2 
after binding: 2 
after binding and dummy2: 101 
nil 
+3

Để tránh lặp lại những tài liệu hướng dẫn, có lẽ bạn có thể mô tả những gì bạn mong đợi và lý do tại sao nó khác với những gì thực sự xảy ra . –

Trả lời

14

Clojure sử dụng cả từ vựng phạm vilet cho các biểu tượng và phạm vi độngbinding cho vars kiểm tra ra tài liệu clojure của vars.

  • "nhập hàm": làm tốt cho đến nay! biểu tượng x giải quyết cho var và điều này là lấy "ràng buộc gốc" của var x.
  • "sau khi để": một liên kết cục bộ bao phủ lên var, ký hiệu x bây giờ là 100 không phải là var.
  • "sau let và dummy2": x trong giả-FN2 đề cập đến var x, vì vậy nó sử dụng rễ ràng buộc của x và trả lại một nhiều hơn thế (+ 1 1)
  • "sau khi ràng buộc ": khó khăn! ràng buộc tự động thay thế ràng buộc gốc của var có tên là x (là 1) với 100, nhưng ký hiệu cục bộ x không phải là var nữa để bạn có được ràng buộc cục bộ.
  • "sau khi ràng buộc và dummy2": các ràng buộc thay thế các giá trị gốc của var x 100 và điều này trở một nhiều hơn thế (+ 100 1)
+0

có vẻ như ràng buộc thay thế "var với tên x", không phải "var mà ký hiệu x giải quyết" là chính xác? –

+0

"var với tên x" có nghĩa là gì? –

+0

Bất kể var nào được trả về bởi (resolve 'x). –

22

let bóng các mục cấp đầu Var x với một địa phương x. let không tạo ra một Var hoặc ảnh hưởng đến Var toplevel; nó liên kết một số biểu tượng sao cho các tham chiếu cục bộ tới biểu tượng đó sẽ được thay thế bằng giá trị let. let có phạm vi từ vựng, do đó các ràng buộc của nó chỉ hiển thị trong chính biểu mẫu let (không phải trong các hàm được gọi từ trong số let).

binding tạm thời (chủ đề cục bộ) thay đổi giá trị của biến thể phức tạp là 01 x, đó là tất cả. Nếu ràng buộc let, binding sẽ không nhìn thấy khi quyết định giá trị nào thay đổi (và các liên kết của let không phải là vars và không thể thay đổi được, do đó 'điều tốt hoặc nó sẽ cho bạn lỗi'). Và binding sẽ không che dấu let. binding có phạm vi động, vì vậy ảnh hưởng của nó đối với các Vars toplevel được hiển thị trong biểu mẫu binding và trong bất kỳ hàm nào được gọi từ bên trong biểu mẫu binding.

Tiếp cận giá trị của đồng bằng cũ x sẽ cung cấp cho bạn bất cứ điều gì là ở phía trên cùng của ngăn xếp của các ràng buộc, một trong hai lồng nhau nhất let giá trị -bound của x (hoặc chức năng paramater gọi x, hoặc một số giá trị x được thay thế bằng nếu bạn sử dụng macro của riêng bạn hoặc các khả năng khác.) và chỉ sử dụng giá trị hiện tại của biến thái to 1 x nếu không có ràng buộc nào khác.

Ngay cả khi biến dạng tobị che khuất bởi let - x, bạn luôn có thể truy cập vào Biến dạng thông qua @#'x. Hãy thử phiên bản này, có thể nó sẽ có ý nghĩa hơn:

(def x 1) 

(defn dummy-fn2[] 
    (println "x from dummy-fn2:" x) 
    (+ x 1)) 

(defn dummy-fn[] 
    (println "entering function:" x) 
    (println "var x:" @#'x) 
    (dummy-fn2) 
    (println "---") 
    (let [x 100] 
    (println "after let:" x) 
    (println "var x:" @#'x) 
    (dummy-fn2) 
    (println "---") 
    (let [x (dummy-fn2)] 
     (println "after let and dummy-fn2:" x) 
     (println "var x:" @#'x) 
     (dummy-fn2) 
     (println "---") 
     (binding [x 888] 
     (println "after binding:" x) 
     (println "var x:" @#'x) 
     (dummy-fn2) 
     (println "---") 
     (let [x (dummy-fn2)] 
      (println "after binding and dummy2:" x) 
      (println "var x:" @#'x) 
      (dummy-fn2) 
      (println "---")))))) 

Cung cấp:

entering function: 1 
var x: 1 
x from dummy-fn2: 1 
--- 
after let: 100 
var x: 1 
x from dummy-fn2: 1 
--- 
x from dummy-fn2: 1 
after let and dummy-fn2: 2 
var x: 1 
x from dummy-fn2: 1 
--- 
after binding: 2 
var x: 888 
x from dummy-fn2: 888 
--- 
x from dummy-fn2: 888 
after binding and dummy2: 889 
var x: 888 
x from dummy-fn2: 888 
--- 
+0

Tôi nhận được 'IllegalStateException Không thể tự động liên kết var không động khi tôi chạy mã này. Nó được giải quyết bằng cách thay thế biểu mẫu 'binding' bằng' let' hoặc sử dụng '(def ^: dynamic x 1)' – dkinzer

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