Clojure doseq会产生巨大的代码吗?

时间:2013-03-11 14:54:36

标签: macros clojure code-generation

我最近一直在玩clojure并遇到了一个我不确定如何处理的问题。我有一个带有7个参数的doseq,它扩展到一个巨大的块,几乎超过了最大的类大小。为什么doseq扩展到如此巨大的clojure代码块?

示例:

(def q '(doseq
[p0 (nth (:params operator) 0 (quote (nil)))
p1 (nth (:params operator) 1 (quote (nil)))
p2 (nth (:params operator) 2 (quote (nil)))
p3 (nth (:params operator) 3 (quote (nil)))
p4 (nth (:params operator) 4 (quote (nil)))
p5 (nth (:params operator) 5 (quote (nil)))
p6 (nth (:params operator) 6 (quote (nil)))]
(do-print board (:oname operator) p0 p1 p2 p3 p4 p5 p6)))

然后:

(macroexpand q)

在我的机器上,它提供了大量的代码(97331字节)。这是正常的还是我做错了什么?运算符是一个简单的defrecord。如果有兴趣的话,这里是扩展结果的链接:http://pastebin.com/6gw1q078

编辑:

通过执行相同的操作,但使用 for 形式,我得到的东西要小几个数量级(3653字节):

(def q '(for
[p0 (nth (:params operator) 0 (quote (nil)))
p1 (nth (:params operator) 1 (quote (nil)))
p2 (nth (:params operator) 2 (quote (nil)))
p3 (nth (:params operator) 3 (quote (nil)))
p4 (nth (:params operator) 4 (quote (nil)))
p5 (nth (:params operator) 5 (quote (nil)))
p6 (nth (:params operator) 6 (quote (nil)))]
(do-print board (:oname operator) p0 p1 p2 p3 p4 p5 p6)))

(macroexpand q)

结果在这里:http://pastebin.com/9MAKK3VD

为什么两者之间存在如此巨大的差异? doseq表单看起来很无辜,当我收到错误表示已超出java类大小时,我真的很惊讶。

1 个答案:

答案 0 :(得分:3)

好吧,看一下doseq的较小的宏观扩展揭示了原因:

(loop [seq_2365 (seq [1 2])
       chunk_2366 nil
       count_2367 0
       i_2368 0]
  (if (< i_2368 count_2367)
    (let [x (.nth chunk_2366 i_2368)]
      (do x)
      (recur seq_2365 chunk_2366 count_2367 (unchecked-inc i_2368)))
    (when-let [seq_2365 (seq seq_2365)]
      (if (chunked-seq? seq_2365)
        (let [c__4197__auto__ (chunk-first seq_2365)]
          (recur (chunk-rest seq_2365) c__4197__auto__ (int (count c__4197__auto__)) (int 0)))
        (let [x (first seq_2365)]
          (do x)
          (recur (next seq_2365) nil 0 0))))))

理想情况下,我们只需要最后一个let表单,但doseq会以特定方式发出额外的代码来处理chunked-seq,这样它就会占用第一个块,然后是每个项目chunk执行doseq的主体,依此类推。

这个代码是为doseq中的单个seq生成的,但是当你有第二个seq时,会产生类似的处理chunked-seq的代码,因此它的大小会爆炸。