2016-12-06 67 views
0

我想评估一个宏的参数是否是一个函数。如果是我想返回未评估的功能。否则返回一个不同的功能。像这样:如何在clojure宏中测试未评估函数?

(defmacro func? [function] 
    (if (fn? function) 
    function 
    identity)) 
((func? "oops") 5) ;=> 5 
((func? -) 5)  ;=> 5 

然而上述失败,因为未计算的功能还不是真正功能得到这个工作,我必须使用邪恶的eval:

(defmacro func? [function] 
    (if (fn? (eval function)) 
    function 
    identity)) 
((func? "oops") 5) ;=> 5 
((func? -) 5)  ;=> -5 

如何避免使用在这里评估? 答案必须是宏。

在我的情况下宏功能的原因是,这个宏被用于很多在我的游戏中被调用很多次的函数。该宏是一个输出格式解释器。换句话说,我自己可以这样写,但宏使我的代码更清晰。如果我使用了一个函数而不是这个宏,它会做同样的解释,只需要进行一次,每50ms重复我的游戏大约60次。希望澄清而不是混淆我的情况。

+1

什么是你正在试图解决的实际问题?我不禁想到,那里可能有更好的解决方案。 –

+0

我很抱歉无法与编译时在运行时评估此函数的需求。问题已更新。 –

+0

这有帮助。但是,“输出格式解释器”是什么意思?你可以添加一些例子,说明你真的想要如何使用这个宏(在上下文中)?你的例子没有太大的意义。如何使'((func?“oops”)5)'评估为'5'与你的“解释器”有关? –

回答

2

您需要考虑宏的许多可能的参数,以决定它是否是函数。

  1. 它是一个符号吗?一个号码?一个字符串?
  2. 符号解析为一个函数的变量?
  3. 该符号需要解析哪些名称空间?

假设的功能,以解决居住在当前的命名空间,你可以做这样的事情:

(defn test 
    [] 
    "result") 

(defmacro func? 
    [f] 
    (if (and (symbol? f) 
      (fn? (var-get (ns-resolve *ns* f)))) 
    f 
    identity)) 

(func? test) 
#object[user$test 0x37c27452 "[email protected]"] 

(func? 4) 
#object[clojure.core$identity 0x3a811e64 "[email protected]"] 

ns-resolvevar-get给你一个句柄到适当的函数值(或所有任何值情况f确实是解决某事的符号)。

在当前命名空间的工作解决了所有的功能,例如:

(:require [some.ns :as other-ns]) 

(func? other-ns/valid-fn) 
=> #object[some.ns$valid-fn 0x7207a00b "[email protected]"] 
+0

['resolve'](https://clojuredocs.org/clojure.core/resolve)可以在这里用来代替'ns-resolve'。另外,所有的宏都需要一个隐含的['&env'](http://blog.jayfields.com/2011/02/clojure-and.html)参数,这个参数应该被用来处理本地定义的函数。不幸的是,我不认为'&env'的细节被认为是Clojure的公共API的一部分。 –

+1

另外,你可以简单地使用'deref'(或'@')来取消引用'Var'。 –

2

为什么要使用宏?

(defn func? [function] 
    (if (fn? function) 
    function 
    identity)) 

((func? "oops") 5) ;=> 5 
((func? -) 5)  ;=> -5 

注意#(identity %)只是identity

+0

以上是一个简化示例(不要以为任何人都希望在这里粘贴200行),因为在编译时只应调用一次这些变量。而不是在运行时多次调用。 –

+0

@JasonBasanese您可以关闭评估(在“def”或附属的let中)以避免重复评估。除非你依赖* form *来产生可能的函数,否则我看不出它有助于在宏中构造计算。 – Thumbnail

+0

@JasonBasanese这是有道理的。您的案例让我想起[clojure.spec]中[谓词](https://clojure.org/guides/spec#_predicates)的作用。但这个问题似乎蒙上了一层阴影。也许你可以设法更公开地传达你的困境。 – Thumbnail