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_Macros - Fatal编程技术网

Clojure宏创建函数的同义词

Clojure宏创建函数的同义词,clojure,macros,Clojure,Macros,对于真正知道如何在任何Lisp中编写宏的人来说,这可能是一个简单的方法。我希望能够为函数名定义同义词。我一直在复制和粘贴hacking core.clj来做这件事,但我不想永远成为这样一个笨蛋!显然,将对synoym函数的调用重写为对原始函数的调用的宏是正确的方法。如果我理解您的问题,有一种更简单的方法:将新符号定义为旧函数 user=> (def foo +) #'user/foo user=> (foo 1 2) 3 user=> (def foo +) user=

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

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

user=> (def foo +)
#'user/foo 
user=> (foo 1 2) 
3
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"

def的性能也优于宏方法:

(defmacro foo2 [& args]
  `(+ ~@args))
foo2实际上是+的别名,其行为方式与(重写为+)完全相同,但使用宏时必须返回值的限制除外

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

user=> (def foo +)
#'user/foo 
user=> (foo 1 2) 
3
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"
宏现在更快了 在我的一个项目中,我已经着手(最愚蠢的)重新命名Clojure的一些核心功能。我一直玩得很开心(
fn
变成
λ
loop
变成

首先:

user=>(defn foo1[&args]`(+~@args))
#'用户/foo1
用户=>(foo1 2 3 4)
(clojure.core/+1 2 3 4)
那绝对不是你想要的。此外,现在看来宏肯定是最快的选择。我复制了格雷格的实验,得到了完全不同的结果。您在下面看到的时间都是十次跑步中最好的一次:

user=>(def foo+)
#'用户/foo
用户=>(定义foo1[&args](应用+args))
#'用户/foo1
user=>(defmacro foo2[&args]`(+~@args))
#'用户/foo2
用户=>(时间(点时间[n 1000000](+1 n)))
“运行时间:53.401812毫秒”
用户=>(时间(dotimes[n 1000000](foo 1 n)))
“运行时间:135.675486毫秒”
用户=>(时间(dotimes[n 1000000](foo1-n)))
“运行时间:494.770352毫秒”
用户=>(时间(dotimes[n 1000000](foo2 1 n)))
“运行时间:53.509264毫秒”
此外,我认为,随着函数做得更多,两种方法之间的差异变得无关紧要。这是我最初进行的实验,我发现它们之间没有区别:

user=>(defmacroα[&body]`(reduce~@body))
#'用户/α
user=>(defnβ[&body](应用减少body))
#'用户/β
用户=>(定义γ减少)
#'用户/γ
用户=>(时间(点时间[n 10000](减少+(范围n)))
“运行时间:5466.920266毫秒”
用户=>(时间(点时间[n 10000](α+(范围n)))
“运行时间:5474.532622毫秒”
用户=>(时间(点时间[n 10000](β+(范围n)))
“运行时间:5491.337517毫秒”
用户=>(时间(点时间[n 10000](γ+(范围n)))
“运行时间:5456.271967毫秒”

最后,您要查找的内容可能来自
clojure.contrib.def
。我没有这方面的经验。

我认为这会导致调用原始函数的开销,而reader宏会重写源代码以调用原始函数。或者这不是Clojure vs.(我对)Lisp的理解吗?我应该澄清最后的评论。我相信如果使用def解决方案,有两个函数调用:调用同义词函数foo,它调用原始函数+。宏应该将源代码中对foo的调用转换为解析代码中对+的单个调用。对吗?我不能回答Clojure,但对于Scheme,使用
+
foo
的开销是相同的——符号是经过计算的。(def foo+)不包装
+
,它计算
+
,然后将该函数绑定到
foo
。两种情况下都有一个函数调用。宏是不需要的。@Greg Harman我下面的大部分回复都是支持你的,把它放在你的回复中更有意义,特别是考虑到这次讨论。请随意将您喜欢的内容复制到您的回复中,我将删除我的内容。@Nathan Sanders谢谢,显然这比我对Lisp的理解让我相信的要容易得多@Pinochle感谢Greg和Nathan的宏演示和性能评测。Clojure编译器可能正在寻找对
+
的调用,并进行一些特殊优化。我想是这样的。我一直在尝试更多函数的实验,而
defn
方法似乎是唯一一种速度一直较慢的方法。没有什么比第一个实验的结果更好。你的行
(defn foo1[&args]
(+~@args))`应该是
defmacro
而不是
defn
对吗?为什么你说这个宏“肯定不是你想要的”,而你的测试似乎表明它是。它不是你想要的,正是因为你给出的原因。我提出它是因为它是格雷格答案中的一行…但它是不正确的。注意,我在测试中没有使用这个定义。