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

19 clojure

  • defn =公众
  • defn- =私人

也许我的Clojure编码风格很糟糕 - 但我发现我在Clojure中编写的大多数函数都是我不希望公开的小辅助函数.

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

  • defn =默认为私有,
  • 为了公开一些事情,我必须这样做defn+?

谢谢!

kot*_*rak 17

不,那里没有.

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

  • 不只是没有,它会真正搞乱任何其他Clojurian看这些代码的想法.即使它是可行的,我也会劝阻它. (13认同)

Mic*_*ent 5

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

我几乎从不使用letfn自己。


nha*_*nha 5

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

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

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

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

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

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

  • 总是使用defn,这使一切都公开
  • use defn+(尚不存在)指定程序员哪些函数是他应该使用的公共API的一部分.defn+应该与defn其他方面没有区别.

另请注意,无论如何都可以访问私人功能:

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

;; from another namespace
(#'user/secret) ;;=> "TOP SECRET"
Run Code Online (Sandbox Code Playgroud)

  • 根据我对Ruby的经验,允许不受限制地访问所有内容(只需使用#send作为私有方法).它最终是一个巨大的混乱,经验不足的开发人员倾向于通过做坏事来滥用这种"自由". (3认同)
  • 究竟.如果我在修改别人的功能时犯了错误,那就是我的错.作为程序员,阻止我修改内部是一种侮辱.一切都应该是公开的.只需正确记录任何潜在问题,就不需要私有. (2认同)

Ter*_*ahl 5

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) )
Run Code Online (Sandbox Code Playgroud)