22
  • defn=公开
  • defn-=私人

也许我的 Clojure 编码风格不好——但我发现我在 Clojure 中编写的大多数函数都是我不想公开的小型辅助函数。

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

  • defn= 默认情况下是私有的,
  • 为了公开某些事情,我必须做defn+什么?

谢谢!

4

4 回答 4

17

不,那里没有。

另一种可能对您有用或可能不起作用的方法是声明一个foo.bar.internal命名空间,其中包含您的命名空间使用的所有私有助手foo.bar。当您想在宏扩展中使用私有函数时,这比私有函数声明具有优势。

于 2012-04-23T05:57:18.110 回答
6

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

关于您对 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) )
于 2015-12-26T10:03:36.470 回答
5

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

我几乎从不使用letfn自己。

于 2012-04-24T06:02:09.960 回答
5

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

这就是我不喜欢的原因defn-

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

但是当这个函数重用内部私有函数时,修改起来就更难了。我必须复制粘贴所有这些私人功能。

我知道这是程序员说“这可能会在没有通知的情况下改变”的一种方式。

无论如何,我想要相反的约定:

  • 总是使用defn,这让一切都公开
  • 使用defn+(尚不存在)向程序员指定哪些函数是他应该使用的公共 API 的一部分。defn+应该和defn其他没有什么不同。

另请注意,无论如何都可以访问私有函数:

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

;; from another namespace
(#'user/secret) ;;=> "TOP SECRET"
于 2015-07-06T12:40:51.817 回答