繁体   English   中英

Clojure,在语法引用之外取消引用切片

[英]Clojure, unquote slicing outside of syntax quote

在clojure中,我们可以使用非引号切片~@来扩展列表。 例如

(macroexpand `(+ ~@'(1 2 3))) 

扩展到

(clojure.core/+ 1 2 3)

重新排列语法时,这在宏中很有用。 但是有可能在宏之外使用非引用切片或熟悉的技术而没有 eval吗?

这是eval的解决方案

(eval `(+ ~@'(1 2 3))) ;-> 6

但我宁愿这样做

(+ ~@'(1 2 3))

不幸的是,这会引发错误

IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote-splicing  clojure.lang.Var$Unbound.throwArity (Var.java:43)

起初我认为apply会这样做,事实确实如此

(apply + '(1 2 3)) ; -> 6

但是,宏或特殊形式不是这种情况。 宏显而易见,因为它在应用之前已经扩展,并且无论如何必须是表单中的第一个元素。 虽然特殊形式不是那么明显,但仍然有意义,因为它们不像功能那样是一等公民。 例如,以下引发错误

(apply do ['(println "hello") '(println "world")]) ;-> error

在运行时将列表“应用”到特殊表单的唯一方法是使用非引号切片和eval吗?

Clojure有一个简单的模型,用于加载和执行程序。 略有简化,它是这样的:

  1. 读者从文本流中读取一些源代码;

  2. 这一次一次传递给编译器;

  3. 编译器扩展它遇到的任何宏;

  4. 对于非宏,编译器应用各种简单的评估规则(特殊形式的特殊规则,文字评估自己,函数调用如此编译等);

  5. 编译已编译的代码,并可能更改以下表单使用的编译环境。

语法quote是一个读者功能。 它在读取时由发出列表结构的代码替换:

;; note the ' at the start
user=> '`(+ ~@'(1 2 3))
(clojure.core/seq
  (clojure.core/concat (clojure.core/list (quote clojure.core/+)) (quote (1 2 3))))

只有在语法引用的块的上下文中,读者才能提供~~@这种特殊处理,并且语法引用的块总是生成可以从clojure.core调用少数seq构建函数的形式,否则由引用数据。

这一切都发生在上面列表中的第1步的一部分。 因此,为了使语法引用作为类似apply的机制非常有用,您需要它在流程中的那一点生成正确形状的代码,然后在后续步骤中看起来像所需的“ apply结果”。 如上所述,语法报价总是产生创建表结构的代码,特别是它永远不会返回,看起来就像不带引号的不带引号的表情do S或if小号等等,所以这是不可能的。

这不是问题,因为在给定上述执行模型的情况下合理的代码转换可以使用宏来实现。

顺便说一句, macroexpand通话是在你的榜样其实是多余的,因为语法引号形式已一样的宏扩展(理所应当的,因为+是不是宏):

user=> `(+ ~@'(1 2 3))
(clojure.core/+ 1 2 3)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM