在clojure中,是否可以在其身体内部获取函数的名称,希望在不引入函数定义的新包装的情况下完成?还可以在函数:test
属性的主体内部访问函数的名称吗?
为了激励,这对于某些日志记录情况很有帮助,也可以保持:test
的主体不会更改它所提供的函数名称。
对meta
最接近的简短说明如下;据我所知,在{3}}中没有this
概念提供给meta
。
(defn a [] (:name (meta (var a))))
显然,使用包装器宏很容易实现。
编辑:幸运的是到目前为止还没有人提到lambda组合器。
答案 0 :(得分:2)
有两种方法可以解决您的问题。但是,我怀疑要完全自动化您想要做的事情,您需要定义自己的自定义defn
替换/包装。
首先要意识到的是,所有功能都是匿名的。当我们输入:
(defn hello [] (println "hi"))
我们正在打字:
(def hello (fn [] (println "hi"))
我们正在创建一个符号hello
,指向匿名var
,后者又指向匿名函数。但是,我们可以给函数一个内部名称"像这样:
(def hello (fn fn-hello [] (println "hi")))
现在我们可以通过hello
或从内部使用hello
个fn-hello
符号从外部访问该功能(请不要使用{{1}在这两个地方或你造成很多混乱......即使它是合法的。)
我经常在(否则)匿名函数中使用hello
方法,因为抛出的任何异常都将包含fn-hello
符号,这使得追踪问题的根源变得更加容易(错误的行号)经常从堆栈跟踪中遗漏)。例如,当使用Instaparse时,我们需要一个匿名转换函数的映射,如:
fn-hello
并为每个功能提供"内部名称"使调试更容易,更容易。如果Clojure有更好的错误信息,这可能是不必要的,但这是一个长期(并且迄今尚未实现)的愿望。
您可以在此处找到更多详细信息:https://clojure.org/reference/special_forms#fn
如果你仔细阅读,它声称 {
:identifier fn-identifier
:string fn-string
:integer (fn fn-integer [arg] [:integer (java.lang.Integer. arg)])
:boolean (fn fn-boolean [arg] [:boolean (java.lang.Boolean. arg)])
:namespace (fn fn-namespace [arg] [:namespace arg])
:prefix (fn fn-prefix [arg] [:prefix arg])
:organization (fn fn-organization [arg] [:organization arg])
:contact (fn fn-contact [arg] [:contact arg])
:description (fn fn-description [arg] [:description arg])
:presence (fn fn-presence [arg] [:presence arg])
:revision (fn fn-revision [& args] (prepend :revision args))
:iso-date (fn fn-iso-date [& args] [:iso-date (str/join args)])
:reference (fn fn-reference [arg] [:reference arg])
:identity (fn fn-identity [& args] (prepend :identity args))
:typedef (fn fn-typedef [& args] (prepend :typedef args))
:container (fn fn-container [& args] (prepend :container args))
:rpc (fn fn-rpc [& args] (prepend :rpc args))
:input (fn fn-input [& args] (prepend :input args))
...<snip>...
}
扩展为
(defn foo [x] ...)
虽然您可能需要进行试验,看看这是否已经解决了您正在寻找的用例。它可以在这个示例中看到,我们明确地避免使用内部(def foo (fn foo [x] ...))
名称:
fn-fact
此版本也有效:
(def fact (fn [x] ; fn-fact omitted here
(if (zero? x)
1
(* x (fact (dec x))))))
(fact 4) => 24
所以我们看到&#34;内部名称&#34; (def fact (fn fn-fact [x]
(if (zero? x)
1
(* x (fn-fact (dec x))))))
(fact 4) => 24
(fn-fact 4) => Unable to resolve symbol: fn-fact
隐藏在函数内部,从外部看不见。
第二种方法,如果使用宏,则使用fn-fact
全局数据从源代码访问行号。 In the Tupelo library此技术用于改进
&form
这个方便的宏允许使用单位测试,如:
(defmacro dotest [& body] ; #todo README & tests
(let [test-name-sym (symbol (str "test-line-" (:line (meta &form))))]
`(clojure.test/deftest ~test-name-sym ~@body)))
评估
(dotest
(is (= 3 (inc 2))))
而不是手动输入
(deftest test-line-123 ; assuming this is on line 123 in source file
(is (= 3 (inc 2))))
您可以访问任何宏中的(deftest t-addition
(is (= 3 (inc 2))))
和其他信息,这些信息可以使您的错误消息和/或异常信息对于试图调试问题的不良读者更有用。
除了上面的宏包装器示例之外,还有另一个(涉及更多)相同技术can be seen in the Plumatic Schema library的示例,它们用(:line (meta &form))
包装扩展版本。
您可能还希望查看此问题,以澄清Clojure如何使用&#34;匿名&#34; var作为符号和函数之间的中介:When to use a Var instead of a function?