2012-10-17 5 views
8

tôi đã có một cái nhìn tại các tài liệu tham khảo: http://clojure.org/vars#Vars%20and%20the%20Global%20Environment, http://clojuredocs.org/clojure_core/clojure.core/bindingmục đích thực tế của các vars và ràng buộc năng động của clojure là gì?

cũng như clojure and ^:dynamicClojure Dynamic Binding

tôi vẫn không hiểu tại sao lại có một nhu cầu cho binding ở tất cả như mọi chương trình tôi đã viết đã không có chúng và tôi có thể tìm cách viết các ví dụ theo cách thông thường - điều mà tôi thấy dễ hiểu hơn. Có những ví dụ về các dự án/mô hình lập trình sử dụng điều này không?

ví dụ ... trong động vật nói ví dụ, bạn có thể có được một hiệu ứng tương tự với:

(def dog {:name "Dog" :sound "Woof"}) 
(def cat {:name "Cat" :sound "Meow"}) 

(defn speak [animal] 
    (str (:name animal) " says " (:sound animal)) 

(println (speak dog)) 
(println (speak cat)) 

không macro, không năng động ràng buộc ... vẫn rất sạch sẽ.

+0

Stuart Sierra nói về ý nghĩa của phạm vi động trong Clojure trong bài đăng trên blog này: http://stuartsierra.com/2013/03/29/perils-of-dynamic-scope –

Trả lời

11

Không có Nghiêm một nhu cầu cho họ: như bạn một cách đúng đắn quan sát bạn có thể làm bất cứ điều gì bạn thích mà không binding, và quả thật nếu binding không tồn tại thì bạn có thể tái thực hiện nó tương đối dễ dàng sử dụng các macro và Java ThreadLocal s.

Ràng buộc là hữu ích như một cách để chuyển ngữ cảnh động đến một hàm mà không cần phải chuyển một cách rõ ràng thông số.

Điều này đặc biệt hữu ích khi bạn đang soạn các hàm thứ tự cao hơn lồng nhau và không muốn thêm thông số bổ sung vào mọi hàm trong ngăn xếp cuộc gọi để chuyển một số giá trị cho các hàm mức thấp hơn được nhúng sâu bên trong.

Để xây dựng dựa trên ví dụ của bạn:

(def ^:dynamic *loud-noises* false) 

(defn speak [animal] 
    (str (:name animal) " says " 
      (let [sound (:sound animal)] 
      (if *loud-noises* (.toUpperCase sound) sound)))) 

(speak dog) 
=> "Dog says Woof" 

(binding [*loud-noises* true] 
    (speak dog)) 
=> "Dog says WOOF" 

Lưu ý tôi không cần thêm một tham số bổ sung cho các speak chức năng để có được hành vi khác nhau. Việc thêm một tham số phụ sẽ không quan trọng trong trường hợp này, nhưng hãy tưởng tượng nếu chức năng speak được chôn sâu trong một hàm bậc cao phức tạp .....

Tuy nhiên, tôi nghĩ lời khuyên tốt nhất là tránh ràng buộc động trừ khi bạn thực sự cần nó. Tốt hơn là thêm các tham số rõ ràng nếu bạn có thể: các tham số trực tiếp giúp dễ dàng kiểm tra và lý luận về các hàm.

+1

Tại sao bạn muốn gắn kết thêm tham số cho mọi chức năng trong một hàm lồng nhau sâu sắc? Nếu hàm của tôi gọi '(nói chó)' và '(close-door)', làm thế nào để tôi biết rằng '* tiếng ồn lớn * 'tương ứng với' nói' và không phải là 'cửa gần'? – ToBeReplaced

+2

@ ToBeReplaced Tôi nghĩ rằng bạn làm nổi bật chính xác mối nguy hiểm với ràng buộc động và tại sao thiết kế sử dụng nó phải được xem xét rất cẩn thận.Liên kết động cho phép ngữ cảnh được chuyển qua các lớp nơi bạn _don't_ kiểm soát phần giữa. Ví dụ các chức năng in clojure cho phép dòng đầu ra được phục hồi ngay cả khi được sử dụng bên trong một chức năng của bên thứ ba (mà không có tham số dòng đầu ra). Điều này cũng cho phép thiết lập hành vi cụ thể của luồng nhưng tôi nghi ngờ ràng buộc động thường xa hơn nhiều so với lợi ích trong hầu hết các API. –

+0

xem bài đăng của tôi bên dưới. – zcaudate

1

Chỉ cần theo dõi ví dụ của mikera ở trên .. Tôi có thể thấy lý do tại sao bạn sẽ làm điều đó bằng ngôn ngữ ít diễn cảm hơn, nhưng vì clojure rất biểu cảm, tôi thà viết lại nó ... để đạt được hiệu quả tương tự bằng cách thêm thông số bổ sung để nói ...

(defn speak [animal & opts] 
    (let [sound (:sound animal) 
     sound (if (some #(= % :louder) opts) 
       (.toUpperCase sound) sound)] 
    (str (:name animal) " says " sound))) 


> (speak dog) 
;;=> "Dog says Woof" 
> (speak dog :louder) 
;;=> "Dog says WOOF" 

Chỉ ràng buộc cách để hack một giải pháp nhanh chóng và bẩn nếu bạn không thể thay đổi mã gốc?

+4

bạn không phải lúc nào cũng có khả năng thêm các tham số phụ - nếu bạn đang chuyển các hàm vào mã thư viện chẳng hạn? hoặc nếu các hàm HOF mục đích chung mà bạn không muốn gây ô nhiễm với các tham số chỉ được sử dụng trong một trường hợp đặc biệt? – mikera