2013-02-07 12 views
12

Czasami, patrząc na kod Clojure innych ludzi, widzę to funkcja zdefiniowana przez defn a następnie wywołać za pomocą składni var-środki, na przykład:Wywoływanie funkcji Clojure użyciu var-quote składnia

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 

Dla życia nie potrafię zrozumieć różnicy między tymi dwoma sposobami wywoływania funkcji. Nie mogę znaleźć niczego w dokumentacji evaluation, aby powiedzieć, co się dzieje, gdy operator połączenia jest var, co może sugerować, dlaczego druga forma byłaby preferowana. Obaj wydają się reagować w ten sam sposób na przypisania binding i cytowanie składni.

Czy ktoś może podać próbkę kodu, która ilustruje różnicę między powyższymi (a) i (#'a)?

Edit: wiem, że var-cytat może być używany, aby dostać się do var, która jest zasłonięta przez let leksykalny wiązania, ale to nie wydaje się być w przypadku kodu, który patrzę.

Odpowiedz

16

(#'a) zawsze odnosi się do vara, natomiast (a) może być zasłonięta przez lokalnych powiązań:

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

Ale najbardziej rzeczywiste zastosowania var-cytując połączenia/funkcji nie wzywających bezpośrednio wyrażenia var-quote , ale zamiast buforować jej wartość tak, że konstrukty wyższego rzędu odnoszą się do aktualnej wartości var a zamiast jego wartości, gdy przeszedł w:

(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 

to m ostly przydatny do interaktywnego programowania, w którym zmieniasz niektóre funkcje, które są pakowane w szereg innych funkcji w innych pakietach.

6

Druga forma pozwala na ominięcie ograniczenia prywatności, które clojure stawia na swoim miejscu.

Na przykład, jeśli stworzysz bibliotekę z prywatnymi funkcjami, ale chcesz przetestować je z osobnego obszaru nazw, nie możesz odwoływać się do nich bezpośrednio. Ale można do nich dotrzeć za pomocą składni var var. Jest to bardzo przydatne.

Prywatność jest clojure jest w istocie, to forma automatycznej dokumentacji, w przeciwieństwie do prywatności można zobaczyć w Javie. Możesz ominąć to.

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

Dobra uwaga - teraz, kiedy o tym wspomniałeś, pamiętam, że zrobiłem to sam w przeszłości. Ale kod, na który patrzę, nazywa się nieprywatnym fn, więc myślę, że unikanie buforowania aktualnie związanej wartości jest bardziej prawdopodobnym wyjaśnieniem. – Alex

+0

Ponieważ kod znajduje się w prywatnym repozytorium. Zadałem ogólne pytanie, dostałem dwie dobre odpowiedzi i mogę je zaakceptować, więc przyjąłem odpowiedź, która była dla mnie lepsza. – Alex