Clojure, defn, defn-, public/private, defaults
-
defn
= public
-
defn-
= private
Возможно, у меня плохой стиль кодировки Clojure, но я нахожу, что большинство функций, которые я пишу в Clojure, являются небольшими вспомогательными функциями, которые я не хочу раскрывать.
Есть ли какой-то параметр конфигурации, где:
-
defn
= private по умолчанию,
- и сделать что-то публичное, мне нужно сделать
defn+
?
Спасибо!
Ответы
Ответ 1
Нет. Это не так.
Альтернативным подходом, который может или не может работать для вас, является объявление пространства имен foo.bar.internal
, содержащего все частные помощники, которые используются вашим пространством имен foo.bar
. Это имеет преимущества перед частными декларациями функций, когда вы хотите использовать частные функции в макроразложениях.
Ответ 2
Если "вспомогательные функции", скорее всего, будут использоваться один раз, вы можете выбрать, чтобы сделать их локалями ваших больших функций или написать их как анонимные функции. См. letfn
: http://clojuredocs.org/clojure_core/clojure.core/letfn и http://clojuredocs.org/clojure_core/clojure.core/fn.
Я почти никогда не использую letfn
себя.
Ответ 3
Как указано в @kotarak, нет способа (насколько я знаю) сделать это, и это не желательно.
Вот почему мне не нравится defn-
:
Я узнал, что при использовании различных библиотек Clojure мне иногда нужно немного модифицировать одну функцию, чтобы лучше соответствовать моим конкретным потребностям.
Это часто что-то очень малое, и это имеет смысл только в моем конкретном случае. Часто это всего лишь char или два.
Но когда эта функция повторно использует внутренние частные функции, это затрудняет изменение. Мне нужно скопировать все эти частные функции.
Я понимаю, что это способ программиста сказать, что "это может измениться без предупреждения".
Независимо от того, я хотел бы иметь противоположное соглашение:
- всегда используйте
defn
, что делает все общедоступным.
- используйте
defn+
(еще не существует), чтобы указать программисту, какие функции являются частью общедоступного API, который он должен использовать. defn+
в противном случае не должен отличаться от defn
.
Также обратите внимание, что в доступ к частным функциям:
;; in namespace user
user> (defn- secret []
"TOP SECRET")
;; from another namespace
(#'user/secret) ;;=> "TOP SECRET"
Ответ 4
Красота Clojure, являющаяся Lisp, заключается в том, что вы можете создавать и адаптировать язык в соответствии с вашими потребностями. Я настоятельно рекомендую вам прочитать On Lisp, автор Paul Graham. Теперь он отдает свою книгу бесплатно.
Относительно вашего предложения defn + vs defn vs defn-. Этот звук для меня, как хороший случай для написания собственного макроса. defn
- это функция, а defn-
- макрос. Вы можете просто переопределить их по своему усмотрению или обернуть их самостоятельно.
Здесь следует предложение к реализации, основанное главным образом на собственной реализации Clojure - включая простую утилиту и тест.
(defmacro defn+
"same as Clojure defn, yielding public def"
[name & decls]
(list* `defn (with-meta name (assoc (meta name) :public true)) decls))
(defmacro defn
"same as Clojure 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) )