Clojure宏创建函数的同义词

时间:2009-08-22 04:07:02

标签: clojure macros

对于任何真正知道如何在任何Lisp中编写宏的人来说,这可能是一个简单的方法。我希望能够为函数名定义同义词。我一直在复制和粘贴黑客core.clj这样做,但我不想永远是这样的傻瓜!很明显,一个宏将对synoym函数的调用重写为对原始函数的调用是正确的方法。

2 个答案:

答案 0 :(得分:13)

如果我理解你的问题,那么有一种更简单的方法:将新符号定义为旧函数。

user=> (def foo +)
#'user/foo 
user=> (foo 1 2) 
3

def的表现也优于宏观方法:

(defmacro foo2 [& args]
  `(+ ~@args))

foo2实际上是+的别名,其行为完全相同(被重写为+),除了使用必须返回值的宏的限制。

如果您希望“别名”的行为与原始函数的行为完全相同(在相同的上下文中也可调用),那么您需要使用def来重命名该函数。

user=> (def foo +)

user=> (defn foo1 [& args]
         `(+ ~@args))

user=> (defmacro foo2 [& args]
         `(+ ~@args))

user=> (time (dotimes [n 1000000] (foo 1 n)))
"Elapsed time: 37.317 msecs"

user=> (time (dotimes [n 1000000] (foo1 1 n)))
"Elapsed time: 292.767 msecs"

user=> (time (dotimes [n 1000000] (foo2 1 n)))
"Elapsed time: 46.921 msecs"

答案 1 :(得分:2)

宏现在更快

我已经开始(在我的一个项目中)重命名Clojure的一些核心功能(最确定是愚蠢的)任务。我一直很开心(fn变为λloop变为等等,但我发现自己对表现非常好奇。我认为格雷格五年前的出色回答现在已经出现了部分错误。我正在使用Clojure 1.5.1。

首先:

user=> (defn foo1 [& args] `(+ ~@args))
#'user/foo1
user=> (foo1 1 2 3 4)
(clojure.core/+ 1 2 3 4)

这绝对不是你想要的。而且,现在看起来宏绝对是最快的选择。我复制了Greg的实验并得到了截然不同的结果。您在下面看到的时间是十次运行中最好的:

user=> (def foo +)
#'user/foo
user=> (defn foo1 [& args] (apply + args))
#'user/foo1
user=> (defmacro foo2 [& args] `(+ ~@args))
#'user/foo2
user=> (time (dotimes [n 1000000] (+ 1 n)))
"Elapsed time: 53.401812 msecs"
user=> (time (dotimes [n 1000000] (foo 1 n)))
"Elapsed time: 135.675486 msecs"
user=> (time (dotimes [n 1000000] (foo1 1 n)))
"Elapsed time: 494.770352 msecs"
user=> (time (dotimes [n 1000000] (foo2 1 n)))
"Elapsed time: 53.509264 msecs"

此外,我认为这些方法之间的区别变得无关紧要,因为功能更多。这是我最初运行的实验,我发现它们之间没有区别:

user=> (defmacro α [& body] `(reduce ~@body))
#'user/α
user=> (defn β [& body] (apply reduce body))
#'user/β
user=> (def γ reduce)
#'user/γ
user=> (time (dotimes [n 10000] (reduce + (range n))))
"Elapsed time: 5466.920266 msecs"
user=> (time (dotimes [n 10000] (α + (range n))))
"Elapsed time: 5474.532622 msecs"
user=> (time (dotimes [n 10000] (β + (range n))))
"Elapsed time: 5491.337517 msecs"
user=> (time (dotimes [n 10000] (γ + (range n))))
"Elapsed time: 5456.271967 msecs"

最后,您正在寻找clojure.contrib.def来自{{1}}的{​​{3}}。我没有经验。