clojure宏变量与map的问题

标签 clojure

我无法让 clojure defmacro 执行我想要的操作。我已将实际代码缩减为以下代码片段。

这会创建一些接近我想要的东西。我试图根据传递到宏中的参数有条件地插入(第一个 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_ 不匹配。因此,执行代码会导致错误,因为第二个变量未定义。我怎样才能让这些变量匹配?这就是我想要实现的目标。

出于测试目的,此代码完成我想要的,但我想要在设置 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)

最佳答案

解决方案之一

(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] ])))

您可以将 if 分支中的 (fn [p#]...) 替换为更复杂的函数。

更新2。使用预定义函数形式参数的更简单的解决方案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] ])))

关于clojure宏变量与map的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14271184/

相关文章:

clojure - 运行Clojure程序的典型方法

clojure - Clojure 中 let 和 let* 的区别

concurrency - 如何在 Clojure 中创建一个持续运行的后台进程?

clojure - 在 Clojure 中检测非空 STDIN

clojure - 如何在头脑中阅读 Lisp/Clojure 代码

ClojureScript clojure.set?

clojure - 在 Clojure 中创建自定义空白

vim - 邪恶的 Emacs 模式 : sentence motions and other questions

Clojure 最佳实践 : When to use Metadata?

string - 将字符串序列转换为整数 (Clojure)