Подтвердить что ты не робот

Clojure, defn, defn-, public/private, defaults

  • defn= public
  • defn-= private

Возможно, у меня плохой стиль кодировки Clojure, но я нахожу, что большинство функций, которые я пишу в Clojure, являются небольшими вспомогательными функциями, которые я не хочу раскрывать.

Есть ли какой-то параметр конфигурации, где:

  • defn= private по умолчанию,
  • и сделать что-то публичное, мне нужно сделать defn+?

Спасибо!

4b9b3361

Ответ 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) )