4

如果您阅读问题宏 -> 使用匿名函数,您会发现该->宏不能很好地与匿名函数一起使用。要正确使用宏,您需要了解实现。从这个意义上说,宏是“泄漏的”——API 没有完全隐藏实现。

(足够复杂的)Clojure 宏是否总是存在泄漏的情况?

[比较:C 预处理器也会出现类似的问题,如果不小心处理宏参数,会出现奇怪的副作用。在这种情况下,可以通过将宏参数括在括号中(在宏内部)来解决问题。这并不能解决使用具有可变状态的 C 宏(即每次使用参数都会改变状态)的问题,但也许我们可以忽略函数式语言的这个问题,或者使用它let来避免多次评估。]

4

3 回答 3

6

您不需要了解实现 - 文档字符串非常清楚它是如何工作的。阅读器宏也有据可查 - #(...) 将扩展为 (fn [..] ...)。鉴于这些知识和提供的文档字符串信息,很明显线程匿名函数将不起作用。根本不需要了解实现。

于 2012-05-25T16:15:30.387 回答
5

从这个意义上说,Clojure 宏并没有泄漏。原因 -> 使用 #() 函数出人意料地工作是因为 #() 是阅读器宏,阅读器宏在“常规”宏之前扩展。所以你需要知道:

  1. 宏应该做什么。-> 实际上是一个非常基本的宏,因为文档几乎准确地解释了它是如何扩展的。
  2. 如果您想将阅读器宏扩展为“普通”宏,它会扩展成什么。
于 2012-05-25T16:35:02.550 回答
1

另请注意,如果您将匿名函数包装在括号中,它将起作用:

=> (-> {:a 1 :b 2} :a (#(* 2 %)))
2

写出匿名函数然后对其进行宏扩展很有启发性:

=> (-> {:a 1 :b 2} :a ((fn [el] (* 2 el))))
2

=> (macroexpand-all '(-> {:a 1 :b 2} :a ((fn [el] (* 2 el)))))
((fn* ([el] (* 2 el))) (:a {:a 1, :b 2}))
于 2013-11-04T03:02:43.030 回答