2013-02-07 40 views
12

thoảng khi nhìn vào mã Clojure của người khác, tôi thấy một chức năng được xác định thông qua defn và sau đó được gọi bằng cách sử dụng cú pháp var-báo giá, ví dụ:Gọi chức năng Clojure sử dụng var-quote cú pháp

user> (defn a [] 1) 
#'user/a 
user> (a) ; This is how you normally call a function 
1 
user> (#'a) ; This uses the var-quote syntax and produces the same result 
1 

Đối với cuộc sống của tôi không thể tìm ra sự khác biệt giữa hai cách gọi một hàm này. Tôi không thể tìm thấy bất cứ điều gì trong tài liệu evaluation phải nói gì sẽ xảy ra khi các nhà điều hành của một cuộc gọi là một var mà có thể đề nghị tại sao hình thức thứ hai sẽ được ưa thích. Cả hai dường như đều phản hồi trong cùng một số binding bài tập và trích dẫn cú pháp.

Vì vậy, ai đó có thể vui lòng cung cấp mẫu mã sẽ minh họa sự khác biệt giữa (a)(#'a) ở trên?

Edit: Tôi biết rằng var-quote thể được sử dụng để có được một var đó là lu mờ bởi một ràng buộc let từ vựng, nhưng điều đó dường như không phải là trường hợp trong các mã mà tôi đang nhìn.

Trả lời

16

(#'a) luôn đề cập đến vara, trong khi (a) thể được theo dõi bởi các ràng buộc địa phương:

user> (defn a [] 1) 
#'user/a 
user> (let [a (fn [] "booh")] [(a) (#'a)]) 
["booh" 1] 

Nhưng hầu hết thực tế sử dụng của var-quote cuộc gọi/chức năng không được gọi biểu var-quote trực tiếp , nhưng thay vào đó, hãy lưu giá trị của nó để các cấu trúc bậc cao hơn tham chiếu đến giá trị hiện tại của var a thay vì giá trị của nó khi được truyền vào:

(defn a [] 1) 
(defn my-call [f] (fn [] (+ 1 (f)))) 
(def one (my-call a)) 
(def two (my-call #'a)) 
(defn a [] 2) 

user> (one) 
2 
user> (two) 
3 

Đây là m ostly hữu ích cho sự phát triển tương tác, nơi bạn đang thay đổi một số chức năng được gói trong một loạt các chức năng khác trong các gói khác.

6

Hình thức thứ hai cho phép bạn để phá vỡ những hạn chế bảo mật clojure đặt tại chỗ.

Vì vậy, ví dụ, nếu bạn xây dựng một thư viện với chức năng riêng, nhưng muốn kiểm tra chúng từ một không gian tên riêng biệt, bạn có thể không đề cập trực tiếp với họ. Nhưng bạn có thể nhận được chúng bằng cách sử dụng cú pháp trích dẫn var. Nó rất hữu ích cho việc này.

Bảo mật là clojure là, trong bản chất, một dạng tài liệu tự động, như trái ngược với sự riêng tư mà bạn nhìn thấy trong Java. Bạn có thể vượt qua nó.

user> (defn- a [] 1) 
#'user/a 
user> (ns user2) 
nil 
user2> (user/a) 
CompilerException java.lang.IllegalStateException: var: #'user/a is not public, compiling:(NO_SOURCE_PATH:1) 
user2> (#'user/a) 
1 
user2> 
+0

Điểm tốt - bây giờ bạn đề cập đến điều này, tôi nhớ đã tự mình làm điều này trong quá khứ. Nhưng đoạn code tôi đang nhìn đang kêu gọi một fn không tin, vì vậy tôi nghĩ rằng tránh các bộ nhớ đệm của giá trị hiện-bound là lời giải thích nhiều khả năng. – Alex

+0

Vì mã nằm trong kho lưu trữ riêng tư. Tôi đã đăng một câu hỏi chung, có hai câu trả lời hay, và chỉ có thể chấp nhận một câu trả lời, vì vậy tôi chấp nhận câu trả lời mà tôi cảm thấy tốt hơn khi trả lời cho trường hợp chung. – Alex

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