macros - Clojure 嵌套宏

标签 macros clojure nested

是否可以宏返回宏?我想最大限度地简化代码,我可以使用返回函数的宏来做到这一点。但是,它的开销太大而且速度太慢。为了使代码更具可读性,我没有使用类型提示,但即使使用它们,我的代码也慢了约 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数组。我不想使用 get。我希望宏扩展为 (aget array-name i)。我写了一个扩展为 (fn [n] (aget array-name i)) 的宏,但这是不必要的开销。

(defmacro series [arr]
  `(fn [i#]
     (aget (longs ~arr) (int i#))))

我现在声明系列,例如“date”,并以这种方式调用它 (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/

相关文章:

macros - 使用 Haxe 宏进行条件编译,而不是#if#end

c 继承的实现

clojure:devcards:分离出主应用程序

c++ nlohmann json - 如何测试嵌套对象是否存在或为空

JavaScript:打印嵌套对象的完整路径

c - 将#define X 宏值替换为编译命令中指定的另一个值

c - 使用宏进行函数声明和定义对静态库中符号导出的影响

clojure - 阅读 Little Lisper 会帮助我学习 clojure 吗?

clojure - 让 Leiningen 和 Cygwin 工作

python - 根据多个条件创建列