【问题标题】:When to use ~'some-symbol in Clojure Macro?何时在 Clojure 宏中使用 ~'some-symbol?
【发布时间】:2017-03-09 07:29:55
【问题描述】:

当我阅读 Clojure 的乐趣时,我遇到了一些代码。

(fn [~'key ~'r old# new#]
                  (println old# " -> " new#)

这个声明~'some-symbol的确切行为是什么。

some-symbol#'~another-symbol 或 gensym 之间的区别?

Clojure 的乐趣:(不明白)

您有时会在 Clojure 中看到模式 ~'symbol 用于有选择地在 a 的主体中捕获符号名称的宏 宏。造成这种尴尬 [11] 的原因是 Clojure 的 syntax-quote 尝试解析当前上下文中的符号, 导致完全合格的符号。因此,~' 避免了这种情况 通过取消引用来解决。

【问题讨论】:

  • P.S.虽然我喜欢“Clojure 的乐趣”,但它是一本有点高级的书,您可能希望在阅读 2-4 其他初级/中级书籍后重新阅读它。这是我阅读的第一本 Clojure 书籍,如果没有足够的 Clojure 背景知识,很多主题很难理解。

标签: clojure macros functional-programming lisp clojurescript


【解决方案1】:

您可以在 Tupelo 库中查看带有 the Literate Threading Macro 的示例。我们希望用户输入符号it 并让它被宏识别。这是定义:

(defmacro it->
  "A threading macro like as-> that always uses the symbol 'it' 
   as the placeholder for the next threaded value "
  [expr & forms]
  `(let [~'it ~expr
         ~@(interleave (repeat 'it) forms)
         ]
     ~'it))

这也称为“照应”宏。然后用户创建如下代码:

(it-> 1
      (inc it)                                  ; thread-first or thread-last
      (+ it 3)                                  ; thread-first
      (/ 10 it)                                 ; thread-last
      (str "We need to order " it " items." )   ; middle of 3 arguments
;=> "We need to order 2 items." )

用户在他们的代码中包含特殊符号it,这是宏所期望的(在这种情况下需要&)。

这有点特殊。在大多数情况下,无论用户选择什么符号,您都希望宏能够工作。这就是为什么大多数宏使用(gensym...) 或带有“#”后缀的阅读器版本的原因,如下例所示:

(defmacro with-exception-default
  "Evaluates body & returns its result.  In the event of an exception, default-val is returned
   instead of the exception."
  [default-val & body]
  `(try
     ~@body
     (catch Exception e# ~default-val)))

这是“正常”情况,宏创建一个“局部变量”e#,保证不会与任何用户符号重叠。一个类似的例子展示了spyx 宏创建了一个名为spy-val# 的“局部变量”来临时保存表达式expr 的计算结果:

(defmacro spyx
  "An expression (println ...) for use in threading forms (& elsewhere). Evaluates the supplied
   expression, printing both the expression and its value to stdout, then returns the value."
  [expr]
  `(let [spy-val# ~expr]
     (println (str (spy-indent-spaces) '~expr " => " (pr-str spy-val#)))
     spy-val#))

请注意,对于 (println...) 语句,我们看到了与 '~expr 相反的语法——但这是另一天的话题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    相关资源
    最近更新 更多