2012-10-17 12 views
8

Ben referanslar bir göz vardı: http://clojure.org/vars#Vars%20and%20the%20Global%20Environment, http://clojuredocs.org/clojure_core/clojure.core/bindingclojure'un dinamik vars ve bağlamalarının pratik amacı nedir?

yanı sıra clojure and ^:dynamic ve Clojure Dynamic Binding

binding için ihtiyaç vardır Hala neden anlamıyorum hiç ben olmuş yazdım her program olarak Onlar olmadan ve geleneksel yollarla örnekleri yazmanın yollarını bulabilirim - ki bu daha anlaşılabilir buluyorum. Bunu kullanan projeler/programlama paradigmaları örnekleri var mı?

(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)) 

hiçbir makro, dinamik hala ... bağlama çok temiz: örnek konuşan hayvanda örneğin

..., sen benzer bir etkiyi elde edebilirsiniz.

+0

Stuart Sierra, bu blog yazısında Clojure'daki dinamik kapsamlamanın etkilerini anlatıyor: http://stuartsierra.com/2013/03/29/perils-of-dynamic-scope –

cevap

11

kesinlikle onlar için bir ihtiyaç yoktur: Eğer haklı gözlemlemek olarak size binding olmadan gibi her şeyi yapabilir ve gerçekten eğer binding o zaman makro kullanarak nispeten kolayca Java'nın yeniden hayata olabilir olmasaydı ThreadLocal s.

Bağlama, bir parametreyi açıkça iletmeye gerek olmadan dinamik bağlamı geçirmenin bir yolu olarak yararlıdır.

Özellikle iç içe geçmiş yüksek sıralı işlevler oluşturduğunuzda ve derinliklere gömülü alt düzey işlevlerine bir değer iletmek için çağrı yığındaki her bir işleve fazladan parametreler eklemek istemediğinizde özellikle kullanışlıdır.

sizin örnek üzerine inşa etmek için:

(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" 

Not farklı davranışı elde etmek speak işleve ek parametre eklemek gerek yoktu. Bu durumda ekstra bir parametre eklemek önemsiz olacaktır, ancak speak işlevinin karmaşık bir yüksek mertebeden fonksiyonun içine gömülüp gömülmediğini hayal edin .....

Yine de, en iyi tavsiyenin genel olarak dinamik bağlamayı önlemek olduğunu düşünüyorum. gerçekten buna ihtiyacım var. Yapabilecekleriniz varsa, genellikle parametreler eklemek daha iyidir: Doğrudan parametreler, fonksiyonları test etmeyi ve mantıklı hale getirmeyi kolaylaştırır.

+1

Neden ek parametreler ekleyerek bağlanmayı tercih edersiniz? derin iç içe geçmiş bir işlevdeki her işleve mi? Eğer fonksiyonum (köpek) ve '(kapi-kapi)' i çağırırsa, '' gürültülü seslerin * '' kapalı ''değil' konuşmaya' karşılık geldiğini nasıl bilebilirim? – ToBeReplaced

+2

@ToBeReplaced Bence dinamik bağlama ile tam olarak tehlikeyi vurgularsınız ve bunu kullanan tasarımların neden çok dikkatli bir şekilde ele alınması gerektiğini düşünürsünüz.Dinamik bağlama, içeriğin ortadaki denetimi yapamadığınız katmanlara aktarılmasına izin verir. Örneğin, clojure yazdırma işlevleri, üçüncü parti işlevinde kullanıldığında (bir çıkış akışı parametresine sahip olmayan) çıkış akımının geri tepmesine izin verir. Bu ayrıca, iş parçacığına özgü davranışı ayarlamaya izin verir, ancak dinamik bağlamanın çoğu API'da faydalı olmaktan çok daha zararlı olduğundan şüpheleniyorum. –

+0

benim yazımı aşağıya bakın. – zcaudate

1

Yukarıdaki mikera'nın örneğini takip ediyorum .. Bunu neden daha az etkileyici bir dilde yapacağınızı görebiliyorum ama clojure çok etkileyici olduğu için yeniden yazmayı tercih ederim ... loud-noise fonksiyonu tekrar hafifçe değiştirilebilir

(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" 

özgün kod değiştiremiyorsanız hızlı ve kirli çözüm doğramaya sadece bir yol bağlayıcı mı ... konuşmayı ek parametreler ekleyerek aynı etkiyi elde etmek için?

+4

, her zaman ek parametreler ekleme yeteneğine sahip değilsiniz - örneğin işlevleri kitaplık koduna geçiriyorsanız ne olur? veya işlevler genel amaçlı HOF'lar ise, sadece bir özel durumda kullanılan parametrelerle kirletmek istemez misiniz? – mikera