Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 获取函数';其主体中的名称或:测试主体_Clojure - Fatal编程技术网

Clojure 获取函数';其主体中的名称或:测试主体

Clojure 获取函数';其主体中的名称或:测试主体,clojure,Clojure,在clojure中,是否可以习惯性地在函数体中获取函数名,希望在不引入新的函数定义包装器的情况下实现这一点?还可以在函数的:test属性的主体内访问函数名吗 出于动机,这有助于某些日志记录情况,也有助于保持:test的主体不受所提供函数名称更改的影响 下面简要说明meta得到的最接近值;据我所知,在clojure中没有这个概念提供给meta (defn a [] (:name (meta (var a)))) 显然,使用包装器宏很容易实现 编辑:幸运的是,到目前为止还没有人提到lambda c

在clojure中,是否可以习惯性地在函数体中获取函数名,希望在不引入新的函数定义包装器的情况下实现这一点?还可以在函数的
:test
属性的主体内访问函数名吗

出于动机,这有助于某些日志记录情况,也有助于保持
:test
的主体不受所提供函数名称更改的影响

下面简要说明
meta
得到的最接近值;据我所知,在clojure中没有
这个
概念提供给
meta

(defn a [] (:name (meta (var a))))
显然,使用包装器宏很容易实现


编辑:幸运的是,到目前为止还没有人提到lambda combinator。

有两种方法来解决您的问题。然而,我怀疑要完全自动化您想要做的事情,您需要定义自己的定制
defn
replacement/wrapper


首先要认识到的是,所有函数都是匿名的。当我们键入:

(defn hello [] (println "hi"))
我们真的在打字:

(def hello (fn [] (println "hi"))
我们正在创建一个符号
hello
,该符号指向一个匿名
var
,该变量反过来指向一个匿名函数。但是,我们可以给函数一个“内部名称”,如下所示:

因此,现在我们可以通过
hello
从外部访问该功能,或者从内部使用
hello
fn hello
符号访问该功能(请不要在两个位置都使用
hello
,否则会造成很多混乱……即使这是合法的)

我经常在(否则)匿名函数中使用
fn hello
方法,因为抛出的任何异常都将包含
fn hello
符号,这使得跟踪问题源变得更加容易(堆栈跟踪中经常缺少错误的行号)。例如,使用Instaparse时,我们需要匿名转换函数的映射,如:

   {
     :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>...
     } 
尽管您可能需要进行实验,看看这是否已经解决了您正在寻找的用例。它以任何一种方式工作,如本例所示,我们明确避免了内部的
fn事实
名称:

(def fact (fn [x] ; fn-fact omitted here
            (if (zero? x) 
              1 
              (* x (fact (dec x))))))

(fact 4) => 24
此版本也适用于:

(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
隐藏在函数内部,从外部看不到


如果使用宏,第二种方法是使用
&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))))
您可以访问任何宏中的
(:line(meta&form))
和其他信息,这些信息可以使错误消息和/或异常对试图调试问题的差劲读者提供更多信息

除了上面的宏包装器示例之外,还有另一个(更复杂的)相同技术的示例,它们使用扩展版本包装
clojure.core/defn



您可能还希望查看此问题,以澄清Clojure如何使用“匿名”变量作为符号和函数之间的中介:

并不是说它有什么区别,而是
(defn hello[](println“hi”)
实际上是
(def hello(fn hello[](println“hi”))
,因为函数允许递归。本地名称似乎被完全忘记了。@阿兰·汤普森非常感谢!我在这里学到了很多东西,不仅仅是逐点的问题,这次讨论真的很有趣excellent@thumbnail阿兰·汤普森:我不认为最初交换的几条评论会在网上增加任何信息nswer目前的措辞……我是否可以建议立即删除它们(?)如果我没有曲解任何东西的话,因为答案被相应地更新后,它们现在有点令人困惑。有一条评论是,对于我原始问题的宏解决方案,我发现只需将
defn
,这样宏就可以将函数名填充到函数体中,相当于o这个答案中的宏示例。
meta
甚至不需要,尽管这无疑是很好的、实用的测试包装灵感!是的,我认为围绕
defn
的宏包装是实现目标的最佳方式。有关Plumatic模式示例的链接,请参阅上面的编辑。
(deftest test-line-123   ; assuming this is on line 123 in source file
  (is (= 3 (inc 2))))
(deftest t-addition
  (is (= 3 (inc 2))))