Clojure,defn,defn-,public / private,默认值

时间:2012-04-23 05:26:16

标签: clojure

  • defn = public
  • defn- = private

也许我的Clojure编码风格很糟糕 - 但我发现我在Clojure中编写的大多数函数都是小助手函数,我不想公开。

是否有一些配置选项,其中:

  • defn =默认为私有,
  • 并公开宣传,我必须defn+

谢谢!

4 个答案:

答案 0 :(得分:17)

没有。没有。

可能或可能不适合您的替代方法是声明一个foo.bar.internal命名空间,其中包含foo.bar命名空间使用的所有私有帮助程序。当你想在宏扩展中使用私有函数时,这比私有函数声明更有优势。

答案 1 :(得分:5)

正如@kotarak所说,没有办法(据我所知)这样做,也不可取。

这就是为什么我不喜欢defn-

我发现当使用各种Clojure库时,我有时需要稍微修改一个函数以更好地满足我的特定需求。 它通常很小,只有在我的特定情况下才有意义。通常这只是一两个字符。

但是当这个函数重用内部私有函数时,它会使修改变得更加困难。我必须复制粘贴所有这些私有函数。

我理解这是程序员说的一种方式,这可能会在没有通知的情况下发生变化"。

无论如何,我想要相反的惯例:

  • 始终使用defn,这会使所有内容公开
  • 使用defn+(尚不存在)向程序员指定哪些函数是他应该使用的公共API的一部分。 defn+应该与defn无异。

另请注意,无论如何都可以access private functions

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

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

答案 2 :(得分:5)

Clojure作为Lisp的美妙之处在于,您可以构建和调整语言以满足您的需求。我强烈建议您阅读On Lisp, by Paul Graham。他现在免费赠送他的书。

关于你对defn + vs defn vs defn-的建议。这听起来像是写一个自己宏的好例子。 defn是一个函数,defn-是一个宏。您可以根据需要重新定义它们,或者将它们包装在您自己的中。

以下是对实现的建议,主要基于Clojure自己的实现 - 包括一个简单的实用程序和一个测试。

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

答案 3 :(得分:4)

如果“辅助函数”很可能只使用一次,您可以选择将它们作为较大函数的本地函数,或者将它们写为匿名函数。请参阅letfnhttp://clojuredocs.org/clojure_core/clojure.core/letfnhttp://clojuredocs.org/clojure_core/clojure.core/fn

我自己几乎不用letfn