【问题标题】:Alternative Clojure Threading Macro替代 Clojure 线程宏
【发布时间】:2017-01-09 00:10:00
【问题描述】:

我在尝试编写线程宏时遇到了一点问题。我发布了一个精简版来说明我遇到了什么问题。

(defmacro <->
  [v & fs]
  `(do
    (-> ~v ~@fs)
    ~v))

该宏相当于线程优先->宏,但它不是返回线程操作的结果,而是返回它传递的原始值。

我遇到的麻烦是,当我执行以下操作时:

(<-> 1 
     (<-> println)
     (<-> println))

我希望输出是

1
1
=> 1

但由于宏从外向内求值,宏展开看起来像:

(do 
  (do 
    (println 
      (do 
        (println 1) 
        1)) 
    (do 
      (println 1) 
      1)) 1)

结果是

1
1
1
=> 1

我可以看到为什么会发生这种情况,因为宏是从外向内评估的,但我不确定如何修复它,因此宏实际上可以按预期工作(即在将其线程化到下一个表单之前评估值 v) .

【问题讨论】:

  • 顺便说一句,您要实现的目标听起来像 doto 宏。不妨看看它的来源。
  • 这是一个我不知道的有用函数,但我不确定它是否会线程化结果......看起来每个表单都采用初始值而不是前一个表单生成的值
  • 您可以通过多种方式组合它们以获得线程和副作用。 (doto x (-&gt; (f) (println)) (-&gt; (g) (println))) 扩展为 (let [x# x] (println (f x#)) (println (g x#)) x#)

标签: clojure macros


【解决方案1】:

您的宏扩展为其中其v 参数被计算两次的形式。您只需要评估一次v,然后let-bind 结果,以便您以后可以参考该值。

(defmacro <-> [v & fs]
  (let [$v (gensym "$v_")]
    `(let [~$v ~v]
       (-> ~$v ~@fs)
       ~$v)))

注意使用gensym 来生成新符号。

【讨论】:

  • 我认为我实际上理解错误,这澄清了它,谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 2020-05-29
  • 2019-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
相关资源
最近更新 更多