是否可以宏返回的宏?我想最大限度地简化代码,我可以使用返回函数的宏来做到这一点。但是,它的开销太大,而且速度太慢。为了使代码更具可读性,我没有使用类型提示,但即使使用它们,我的代码也慢了大约 5 倍。
我的英语不是很精确,所以我写了我所拥有的和我想要的。
我有这个...
(defmacro series [java-array]
`(fn
([i#]
(aget ~java-array i#))
([start# stop#]
(let [limit# (unchecked-subtract-int stop# start#)
result# (double-array limit#)]
(loop [i# 0]
(if (< i# limit#)
(let [r# (double (aget ~java-array i#))]
(aset result# i# r#)
(recur (inc i#)))
result#))))))
我想要这样的东西...
(defmacro series [java-array]
`(defmacro blabla
([i#]
`(aget ~~java-array i#))
([start# stop#]
`(let [limit# (unchecked-subtract-int stop# start#)
result# (double-array limit#)]
(loop [i# 0]
(if (< i# limit#)
(let [r# (double (aget ~~java-array i#))]
(aset result# i# r#)
(recur (inc i#)))
result#))))))
但是当我调用这个...
Wrong number of args (1) passed to: blabla
一个更简单的例子。
我有很多java数组。我不想使用age。我希望宏扩展为
(aget array-name i)
。我编写了一个扩展为 (fn [n] (aget array-name i))
的宏,但这是不必要的开销。(defmacro series [arr]
`(fn [i#]
(aget (longs ~arr) (int i#))))
我现在声明系列,例如“日期”,并以这种方式调用它
(date i)
,它将返回数组的“i”元素。 最佳答案
我认为您正在寻找的是一种在函数内声明局部宏的方法。 clojure.tools.macro
包有一个 macrolet
形式,我认为你应该能够为本地数组查找创建一个宏。
这是我放在一起的一个小例子:
; project.clj
(defproject testproject "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.5.0"]
[org.clojure/tools.macro "0.1.2"]])
; src/testproject/core.clj
(ns testproject.core
(:require [clojure.tools.macro :refer [macrolet]]))
(defn my-test []
(let [n 1000
arr (int-array n (range 10))]
(macrolet [(lookup [i] (list `aget 'arr i))]
(loop [i 0, acc 0]
(if (< i n)
(recur (inc i) (+ acc (lookup i)))
acc)))))
在示例中,我使用
macrolet
来声明一个名为 lookup
的宏,该宏将导致 (lookup 5)
扩展为 (lookup arr 5)
,这就是我认为您正在寻找的内容。请注意,在本地宏定义中引用
arr
时必须小心。如果您只是将宏声明为 `(aget arr ~i)
,那么它会尝试查找不存在的完全限定符号 arr
。您也可以将宏声明为 `(aget ~'arr ~i)
,但我觉得 (list `aget 'arr i)
看起来好多了。现在您可以更进一步,使用
defmacro
创建一个包含 macrolet
的宏,您可以使用它来简化具有本地查找宏的数组声明。我们将此作为练习留给读者。由于宏是如此微妙,并且在宏中嵌套宏只会让事情变得更糟,我认为仅举一个例子并让您弄清楚它是如何工作的可能会更有帮助:
(defmacro lookup-binding [[fn-sym value] & body]
(let [array-sym (symbol (str fn-sym "-raw"))]
`(let [~array-sym ~value]
(macrolet [(~fn-sym [i#] (list aget '~array-sym i#))]
~@body))))
(defn my-test2 []
(let [n 1000]
(lookup-binding [arr (int-array n (range 10))]
(loop [i 0, acc 0]
(if (< i n)
(recur (inc i) (+ acc (arr i)))
acc)))))
免责声明: 我只是想表明这是可能的,而不是一个好主意。我个人认为所有这些额外的复杂性都不值得避免
aget
。我建议只使用 aget
因为它只有几个额外的字符,它会让你的代码更清晰/可读。关于macros - Clojure 嵌套宏,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24091240/