clojure宏变量与地图的麻烦

时间:2013-01-11 03:26:32

标签: clojure

我无法让clojure defmacro做我想做的事。我已将实际代码减少到以下代码段。

这会创建 close 到我想要的东西。我试图有条件地插入(第一个p#)或(第二个p#),具体取决于传入宏的参数。

(defmacro mmz1 [t]
  `(map (fn [p#] (let [t1# (first p#)
                      t2# ~(if t `(first p#) `(second p#))]
                  (* t1# t2#)))
        [ [1 2] [3 4] ]))

(macroexpand-1 '(mmz1 false))

显示

(map
  (fn [p__18341__auto__]
    (let [t1__18342__auto__ (first p__18341__auto__)
          t2__18343__auto__ (second p__18340__auto__)]
      (* t1__18342__auto__ t2__18343__auto__)))
  [[1 2] [3 4]])

但请注意,此表单中的变量(第二个p_ 18340 _auto_ )与匿名函数参数p _18341_ auto _不匹配。因此,执行代码会导致错误,因为未定义第二个var。我怎样才能让这些变量匹配?这就是我想要完成的事情。

出于测试目的,此代码完成我想要的内容,但我希望在生成的宏代码中设置t2#的(if)表单。一个宏应该允许我这样做 - 不应该吗?

(defmacro mmz0 [t]
  `(map (fn [p#] (let [t1# (first p#)
                      t2# (if ~t (first p#) (second p#))]
                  (* t1# t2#)))
        [ [1 2] [3 4] ]))

(macroexpand-1 '(mmz0 false))

显示

(map
  (fn [p__18387__auto__]
    (let [t1__18388__auto__ (first p__18387__auto__)
          t2__18389__auto__ (if false
                              (first p__18387__auto__)
                              (second p__18387__auto__))]
      (* t1__18388__auto__ t2__18389__auto__)))
  [[1 2] [3 4]])

并且代码的输出是预期的:

(mmz0 false) -> (2 12)

2 个答案:

答案 0 :(得分:3)

其中一个解决方案

(defmacro mmz1 [t]
  `(map (fn [p#] (let [t1# (first p#)
                       t2# (~(if t 'first 'second) p#)]
                   (* t1# t2#)))
        [ [1 2] [3 4] ]))

<强>更新即可。更一般的解决方案

(defmacro mmz1 [t]
  (let [trg-fn (if t 
                 `(fn [p#] (first p#)) 
                 `(fn [p#] (second p#)))]
    `(map (fn [p#] (let [t1# (first p#)
                         t2# (~trg-fn p#)]
                   (* t1# t2#)))
        [ [1 2] [3 4] ])))

您可以使用更复杂的功能替换(fn [p#]...)分支中的if

Update2。使用预定义函数形式参数p的简单解决方案

(defmacro mmz1 [t]
  (let [p `p#]
   `(map (fn [~p] (let [t1# (first ~p)
                        t2# ~(if t `(first ~p) `(second ~p))]
                    (* t1# t2#)))
         [ [1 2] [3 4] ])))

答案 1 :(得分:0)

必须指出,这根本不需要是一个宏。

等效功能更具可读性和可组合性,因此我建议您使用它。