2

我想出了下面的函数,它按预期工作,但它使用了 eval,这很可怕,并且在我打算使用它的 ClojureScript 中不存在。

(defn path [d p]
  (eval 
    (concat '[-> d] 
      (flatten (map 
                 #(conj (repeat (dec %) 'z/right) 'z/down) 
                 (path-to-vector p))))))

我如何将其转换为宏?我的尝试如下所示:

(defmacro path [d p]
  `(concat (-> ~d)
      (flatten
       (map #(conj (repeat (dec %) z/right) z/down)
             (path-to-vector ~p)))))

但这显然行不通。

4

2 回答 2

4

不需要宏或评估,操作只是reduce

(defn path [d p]
  (reduce (fn [s v]
            (reduce #(%2 %1) s (conj (repeat (dec v) z/right) z/down)))
          d (path-to-vector p)))

另请注意,这(conj (repeat (dec %) z/right) z/down)意味着 z/down 然后所有 z/right coz 重复返回一个序列,如果您希望所有 z/right 第一个和最后一个项目应该是 z/down 那么您应该使用(conj (vec (repeat (dec %)) z/right) z/down)

于 2013-05-08T16:31:44.500 回答
1

Ankur 是正确的,这是 reduce 的情况,宏或 eval 都不合适,尽管为了它自己的缘故,可能仍然值得解释编写这样的宏的机制:

您的宏示例非常接近,您只需要使用 splicing-unquote 函数即可使其工作:

(defmacro path [d p]
  `(-> ~d 
      ~@(flatten
         (map #(conj (repeat (dec %) z/right) z/down)
               (path-to-vector ~p)))))

这会在宏扩展时评估对 flatten 的调用,然后将其连接到生成的 s-expression/list 中。

于 2013-05-08T18:11:10.117 回答