【问题标题】:Text replacement capability in clojure macros like C's #defineclojure 宏中的文本替换功能,如 C 的 #define
【发布时间】:2019-06-26 00:40:59
【问题描述】:

我想写一个宏

(defmacro params [] 'a 'b 'c)

将在这样的地方使用

;; without macro
(fnc a b c)

;; with macro
(fnc params) => (fnc a b c)

如果您发现这可以通过 C 的 #define 轻松完成,这只是一个文本替换

但这只是返回一个'c

【问题讨论】:

  • 您能否补充一下您为什么要这样做(一个更完整的示例)?
  • 我观察到我正在编写的函数有一个共同的模式。即我定义了一个带有参数 a,b,c 的函数。现在这个函数的主体调用了许多具有相同参数的其他函数。现在我不想到处重写 a,b,c。如果每个 defns arglist 都有一个像上面这样的宏,那么我可以在我输入 a、b、c 的函数调用的地方使用它。但是我认为我可以使用 postwalk-replace 之类的代码转换工具来实现这一点。如果我仍然不清楚@AlanThompson,请告诉我

标签: clojure macros lisp


【解决方案1】:

我不太确定为什么您要这样做,但在 clojure 中通常会使用以下惯用语:

(defmacro with-params
  [params fncall]
  `~(concat fncall params))

(defn myfn [x y z]
  (spyx :myfn [x y z]))

(let [a 1
      b 2
      c 3]
  (println :with-params)
  (with-params [a b c]
    (myfn))

结果:

:with-params
:myfn [x y z] => [1 2 3]

但是,如果您想硬编码代码以始终使用参数 a、b 和 c,您可以这样做:

(defmacro with-params-abc
  [fncall]
  `~(concat fncall '[a b c]))

(println :with-params-abc)
(with-params-abc
  (myfn))

结果:

:with-params-abc
:myfn [x y z] => [1 2 3]

【讨论】:

    【解决方案2】:

    Lisp 风格宏的要点是它们在 code 上运行,而不是在 text 上(或者更具体地说,在 抽象语法树上而不是 token 序列),这使得它们比 C 预处理器更有用。

    您实际上的意思是说该函数将使用三个参数调用,这些参数恰好是每个调用站点上同名变量的值。这是相当多的假设。让我们看看实际情况如何:

    (def-magic-splat-macro params    ; whatever, doesn't exist
      a b c)
    
    (defn foo [a]
      (let [b (frob a)
            c (blah)]
        (func params)))  ; What the hell
    

    除了混淆之外,我看不出这有什么用处。

    如果要定义标准参数:

    (def standard-params [1 "quux" :never])  ; values!
    
    (defn foo [bar]
      …
      (apply func standard-params))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-27
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2014-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多