Clojure,defn,defn-,公共/私有,默认值 defn=公共 defn-=private

Clojure,defn,defn-,公共/私有,默认值 defn=公共 defn-=private,clojure,Clojure,也许我的Clojure编码风格不好——但我发现我在Clojure中编写的大多数函数都是我不想公开的小助手函数 是否有一些配置选项,其中: defn=默认情况下为私有 为了公开一些东西,我必须执行defn+ 谢谢 没有。没有 另一种可能适用于您,也可能不适用于您的方法是声明一个foo.bar.internal名称空间,其中包含foo.bar名称空间使用的所有私人助手。当您希望在宏扩展中使用私有函数时,这比私有函数声明有优势。如果“帮助函数”很可能只使用一次,您可以选择将它们作为较大函数的局部函

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

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

  • defn
    =默认情况下为私有
  • 为了公开一些东西,我必须执行
    defn+
谢谢

没有。没有

另一种可能适用于您,也可能不适用于您的方法是声明一个
foo.bar.internal
名称空间,其中包含
foo.bar
名称空间使用的所有私人助手。当您希望在宏扩展中使用私有函数时,这比私有函数声明有优势。

如果“帮助函数”很可能只使用一次,您可以选择将它们作为较大函数的局部函数,或者将它们作为匿名函数编写。请参见
letfn
:和


我自己几乎从不使用
letfn

正如@kotarak所说的,没有办法(据我所知)做到这一点,也不可取

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

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

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

我理解这是程序员说“这可能会在不通知的情况下更改”的一种方式

不管怎样,我想要相反的惯例:

  • 始终使用
    defn
    ,这会使所有内容公开
  • 使用
    defn+
    (还不存在)向程序员指定哪些函数是他应该使用的公共API的一部分
    defn+
    应与
    defn
    相同,否则
另外,请注意,无论如何都可以:


Clojure作为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) )

不只是没有,它会让其他Clojurian人看这些代码时的思维混乱。即使它是可行的,我也会阻止它。我认为这些助手函数的大小无关紧要。如果它们被多次使用,那么它们真的应该被抽象为代码。我真的看不出有什么理由让它们成为本地/匿名的,除非它们在本地只使用一次。这是真的。我将修改答案。我曾尝试为我的助手使用
letfn
,但这使我的代码太乱。因此,在很短的一段时间后,我切换回
defn-
。根据我使用Ruby的经验,Ruby允许不受限制地访问所有内容(只需使用#send for private方法)。结果是一团糟,经验不足的开发人员往往会通过做一些非常糟糕的事情来滥用这种“自由”。在编写了一个大的clojure代码库之后,我实际上为private
defn-
案例找到了一些价值。我还没有完全尝试使用
defn+
。如果我在修改别人的函数时出错,那是我的错。作为一名程序员,阻止我修改内部代码是一种侮辱。一切都应该公开。只要正确记录任何潜在的问题,就不需要私人文件。@Rebs哇,我有完全相反的观点。API应该保护用户不受其内部复杂性的影响。我可能受到我强大的面向对象背景的影响,但我真的不认为自由修改库的内部内容是一个好主意。曾经。@Dici有时您需要添加或修改其他人代码的内部。没有什么比找到一个需要扩展的类更糟糕的了,但是一切都得到了保护。作为一名程序员,你不可能想到所有可能的事情。将内部标记为“请不要碰”Python风格(\u var,\u method),但不要阻止我。设置的障碍越多,我的代码就必须越详细,才能克服这些障碍。编写具有层次而非屏障的API。增加价值,不要删除它。你真的不信任其他程序员吗?为什么要编写偏执狂库代码?
(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) )