宏字符串插值/如何在字符串中取消引用?

Macro string Interpolation / How to unquote inside string?

我有一个像这样的宏:

(defmacro test [x] `"~x")

在 运行 之后扩展为以下内容:

=> (test abc)
'~x'

为什么不扩展到 'abc'

在字符串中取消引号的正确方法是什么?

我不明白你为什么希望它起作用,我不清楚你想要什么。 ~ 在你的例子中是一个字符串文字,所以它是一个普通的字符串字符,而不是 ~ 运算符,与 ((fn [x] "x") 5) returns "x" 和不是 "5".

如果您想将传递给宏的模型字符串化,请使用 str,如下所示:

hy 1.0a1+114.g2abb33b1 using CPython(default) 3.8.6 on Linux
=> (defmacro test [x] (str x))
<function test at 0x7fe0476144c0>
=> (test abc)
"abc"

我认为这里有一个更普遍的问题:如何在 macro-expansion 时使用字符串插值?

答案是要记住,反引号前缀 ~ 可以应用于 任何形式 ,而不仅仅是空符号,它只是 shorthand unquote.

因此您可以只使用 f-string,并取消引用 f-string。使用原始示例:

(defmacro test [x]
  (quasiquote (unquote f"{x}")))

或使用shorthand前缀符号:

(defmacro test [x]
  `~f"{x}")

~f"{module} ..." 对 `(unquote f"{module} ...") 有效 shorthand。

作为使用 ~ 的任意形式的另一个示例,您可以使用 str.format 而不是 f-string:

(defmacro test [x]
  `~(.format "{}" x))

作为一个real-world例子,这是我今天写的一个宏:

(import sys
  typing [NoReturn])

(defn ^NoReturn die [^int status ^str message]
  (print message :file sys.stderr)
  (sys.exit status))

(defmacro try-import [module]
  `(try
     (import ~module)
     (except [ImportError]
       (die 1 ~f"{module} is not available, exiting."))))