2012-04-23 12 views
18
  • defn = publicznej
  • defn- = prywatny

Może mam zły styl kodowania Clojure - ale uważam, że większość funkcji piszę w Clojure to małe funkcje pomocnicze, których nie chcę ujawniać.Clojure, defn, defn-, publiczne/prywatne, domyślnie

Czy jest jakaś opcja konfiguracji, gdzie:

  • defn = prywatny domyślnie
  • i zrobić coś publicznej, muszę zrobić defn+?

Dzięki!

Odpowiedz

16

Nie. Nie ma.

Alternatywnym podejściem, które może, ale nie musi, jest zadeklarowanie przestrzeni nazw foo.bar.internal zawierającej wszystkie prywatne helpery używane w przestrzeni nazw foo.bar. Ma to przewagę nad deklaracjami funkcji prywatnych, gdy chcesz używać funkcji prywatnych w ekspansjach makro.

+12

Nie tylko to, że nie jest, byłoby naprawdę nieładne z umysłem jakiegokolwiek innego Clojuriana patrzącego na taki kod. Zniechęciłbym go, nawet gdyby było to wykonalne. –

4

Jeśli "funkcje pomocnicze" najprawdopodobniej zostaną użyte jednokrotnie, możesz zdecydować, że będą one lokalnymi większymi funkcjami lub zapisać je jako funkcje anonimowe. Zobacz letfn: http://clojuredocs.org/clojure_core/clojure.core/letfn i http://clojuredocs.org/clojure_core/clojure.core/fn.

Ja sam rzadko używam numeru letfn.

+0

Nie sądzę, że rozmiar tych funkcji pomocnika ma znaczenie. Jeśli są używane więcej niż jeden raz, powinny zostać wyodrębnione z kodu suszarki. Nie widzę powodu, dla którego byłyby one lokalne/anonimowe, chyba że są używane tylko raz na miejscu. – tjb1982

+0

To prawda. Dostosuję odpowiedź. –

+0

Próbowałem użyć 'letfn' dla moich pomocników, ale mój kod był zbyt brudny. Tak więc po krótkim czasie przełączyłem się z powrotem na 'defn-'. –

4

Jak stwierdził @kotarak, nie ma sposobu (o ile wiem), aby to zrobić, ani nie jest to pożądane.

Oto dlaczego lubię defn-:

I okazało się, że podczas korzystania z różnych bibliotek Clojure Czasem trzeba nieco zmodyfikować jedną funkcję do lepszego kolorze moich potrzeb. Często jest to coś małego, co ma sens tylko w moim konkretnym przypadku. Często jest to po prostu char lub dwa.

Ale gdy ta funkcja ponownie wykorzystuje wewnętrzne prywatne funkcje, utrudnia jej modyfikację. Muszę skopiować i wkleić wszystkie te prywatne funkcje.

Rozumiem, że jest to sposób, aby programista powiedział, że "to może ulec zmianie bez powiadomienia".

Niezależnie chciałbym przeciwny konwencji:

  • zawsze używać defn, która sprawia, że ​​wszystko publicznego
  • korzystanie defn+ (która jeszcze nie istnieje), aby określić do programatora, które funkcje są częścią publiczny interfejs API, z którego ma korzystać. defn+ nie powinien być inny niż defn w przeciwnym razie.

Również należy pamiętać, że jest to możliwe i tak access private functions:

;; in namespace user 
user> (defn- secret [] 
     "TOP SECRET") 

;; from another namespace 
(#'user/secret) ;;=> "TOP SECRET" 
+2

Z mojego doświadczenia z Ruby, która pozwala na nieograniczony dostęp do wszystkiego (wystarczy użyć #send dla prywatnych metod). Kończy się to wielkim bałaganem, a mniej doświadczeni programiści nadużywają tej "wolności", robiąc naprawdę złe rzeczy. – yagooar

+0

Po pracy nad dużym kodem zaklęć, faktycznie znalazłem wartość dla prywatnego przypadku 'defn-'. Muszę jeszcze spróbować użyć 'defn +'. – nha

+2

Dokładnie. Jeśli popełnię błąd, modyfikując czyjąś funkcję, to moja wina. Jako programista, blokowanie mnie przed modyfikowaniem wewnętrznych elementów jest zniewagą. Wszystko powinno być publiczne. Po prostu udokumentuj wszystkie potencjalne problemy poprawnie i nie ma potrzeby, aby były prywatne. – Rebs

4

Piękno Clojure bycia Lisp, jest to, że można zbudować i dostosować język do własnych potrzeb. Gorąco polecam przeczytać On Lisp, by Paul Graham. Teraz oddaje swoją książkę za darmo.

Odnośnie twojej sugestii defn + vs defn vs defn-. Ten dźwięk jest dla mnie dobrym przykładem do napisania własnego makra. defn to funkcja, a defn- to makro. Możesz po prostu przedefiniować je według własnego uznania lub owijać je własnymi.

Poniżej znajduje się sugestia wdrożenia, oparta głównie na własnej implementacji Clojure - w tym proste narzędzie i test.

(defmacro defn+ 
    "same as Clojure's defn, yielding public def" 
    [name & decls] 
    (list* `defn (with-meta name (assoc (meta name) :public true)) decls)) 

(defmacro defn 
    "same as Clojure's defn-, yielding non-public def" 
    [name & decls] 
    (list* `defn (with-meta name (assoc (meta name) :private true)) decls)) 

(defn mac1 
    "same as `macroexpand-1`" 
    [form] 
    (. clojure.lang.Compiler (macroexpand1 form))) 

(let [ ex1 (mac1 '(defn f1 [] (println "Hello me."))) 
     ex2 (mac1 '(defn+ f2 [] (println "Hello World!"))) ] 
    (defn f1 [] (println "Hello me.")) 
    (defn+ f2 [] (println "Hello World!")) 
    (prn ex1) (prn (meta #'f1)) (f1) 
    (prn ex2) (prn (meta #'f2)) (f2))