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,我对Clojure很陌生,我想,一般来说,编程都很陌生,但我最终尝试编写某种DSL来生成PDF文件(使用PDFBox,一个java库)。 我希望最后的语法如下所示: (document {:name "test" :bleed "22mm" ...} (page {:height "560mm" ...) (text {:color "red"} "blabla") (line-break)) 所以问题是,每个表达式都是一个宏,它将在eval time做一些事情+递归地读取第一个参数后的

我对Clojure很陌生,我想,一般来说,编程都很陌生,但我最终尝试编写某种DSL来生成PDF文件(使用PDFBox,一个java库)。 我希望最后的语法如下所示:

(document {:name "test" :bleed "22mm" ...} 
  (page {:height "560mm" ...) (text {:color "red"} "blabla") (line-break))
所以问题是,每个表达式都是一个宏,它将在eval time做一些事情+递归地读取第一个参数后的每个表达式,并使用
conj
的选项作为第一个参数展开它。例如,现在看起来是这样的:

   (defmacro document
      [{:keys [name] :as options}
       & body]
      `(let [~'pdoc ~'(PDDocument.)]
         (do
           ~@(unfold (conj options {:pdoc 'pdoc}) ~body)
           (doto ~'pdoc
             (...)))
和展开宏(展开参数的宏):

问题是我无法让他们一起工作。经过一些调试后,我仍然得到
java.lang.NullPointerException:

我感觉到问题来自
展开
输出到
文档的方式,但我完全无法了解宏嵌套时的反应。当我使用
macroexpand
时,嵌套宏永远不会展开,我不知道这是预期的还是编程错误。不管怎样,什么时候

(macroexpand '(unfold {...} (document) (document)))
我明白了

在我目前的理解中,这似乎是可以的,因为我在之后使用它。但我显然遗漏了什么

---------编辑-----------

为了一个非常无用的

(document {:name "hey"}} (document {:name "ho"}))
最后我想以(
(doto…
为例):

很抱歉,这篇文章很具体,篇幅很长,但我不知道如何解释这个问题,而没有描述所有内容

提前谢谢大家,,
再见

我不确定这是否能解决问题,但有几点建议:

  • 对于
    let
    绑定,请使用
    foo 35;
    而不是
    ~'foo
    以避免命名冲突。末端的锐利会生成随机的机器符号,因此您的范围内没有隐藏的bug
  • 尝试使用
    (macroexpand'(文档{…}))
    展开宏定义,查看其中的内容。您可以在REPL中重新评估结果列表以检查其是否存在错误
  • 最后,暂时避免使用宏。首先尝试用简单的函数实现您的想法。可能足够了

我不确定这是否能解决问题,但有几点建议:

  • 对于
    let
    绑定,请使用
    foo 35;
    而不是
    ~'foo
    以避免命名冲突。末端的锐利会生成随机的机器符号,因此您的范围内没有隐藏的bug
  • 尝试使用
    (macroexpand'(文档{…}))
    展开宏定义,查看其中的内容。您可以在REPL中重新评估结果列表以检查其是否存在错误
  • 最后,暂时避免使用宏。首先尝试用简单的函数实现您的想法。可能足够了

    • 感谢大家的帮助和建议。 现在,我喜欢这样的东西 :

      (defn unfold
        [options body]
        (loop [
           [f & fs] body
           opts options
           output []]
          (if (empty? f)
            output
            (recur fs
                (conj opts (second f))
                (conj output (list (first f) (conj opts (second f)))))))))
      

      它感觉有点粗糙,但它的工作原理和预期的一样。
      无论如何,我现在将尝试研究新的方法和策略。

      感谢大家的帮助和建议。 现在,我喜欢这样的东西 :

      (defn unfold
        [options body]
        (loop [
           [f & fs] body
           opts options
           output []]
          (if (empty? f)
            output
            (recur fs
                (conj opts (second f))
                (conj output (list (first f) (conj opts (second f)))))))))
      

      它感觉有点粗糙,但它的工作原理和预期的一样。
      我现在将尝试研究新的方法和策略。

      您可以添加一个对宏的示例调用,并提供所需的输出吗?您调用的
      unfold
      就像一个函数,但它是一个宏。发出
      展开
      (需要发出
      执行
      才能工作)或使
      展开
      成为功能。另外,请添加整个异常消息。@clojuremotly-Hum我想我明白了。你更喜欢哪种方式?让它成为一个功能似乎更干净。这就是整个异常信息。奇怪的是它是空的…我都见过,所以这是你的偏好。如果需要在代码中使用
      展开
      ,则保留宏。如果
      展开
      仅用于库生成代码,那么一定要将其作为函数。仅供参考:一个宏有两个隐式参数,在像函数一样调用它时不会传入。因此(可能)出现了错误。另外,您似乎不希望
      unfold
      成为一个vararg?您可以添加一个对宏的示例调用,以获得所需的输出吗?您调用
      unfold
      就像调用一个函数,但它是一个宏。发出
      展开
      (需要发出
      执行
      才能工作)或使
      展开
      成为功能。另外,请添加整个异常消息。@clojuremotly-Hum我想我明白了。你更喜欢哪种方式?让它成为一个功能似乎更干净。这就是整个异常信息。奇怪的是它是空的…我都见过,所以这是你的偏好。如果需要在代码中使用
      展开
      ,则保留宏。如果
      展开
      仅用于库生成代码,那么一定要将其作为函数。仅供参考:一个宏有两个隐式参数,在像函数一样调用它时不会传入。因此(可能)出现了错误。而且,您似乎不想
      unfold
      成为一个vararg?
      (let [pdoc (.PDDocument)]
        (do
          (let [pdoc (.PDDocument)]
            (do
              (doto pdoc .save (str "ho" ".pdf"))))
          (doto pdoc .save (str "hey" ".pdf"))))
      
      (defn unfold
        [options body]
        (loop [
           [f & fs] body
           opts options
           output []]
          (if (empty? f)
            output
            (recur fs
                (conj opts (second f))
                (conj output (list (first f) (conj opts (second f)))))))))
      
      (defmacro document
        [{:keys [name] :as options}
        & body]
        `(let [~'pdoc ~'(PDDocument.)]
          (do
            ~@(map macroexpand
                (unfold (conj options {:pdoc 'pdoc}) body))
            (doto ~'pdoc
                  (...)))))