为什么在准引用列表的末尾可以对非列表使用取消引用拆分? [英] Why is it possible to use unquote-splicing on a non-list at the end of a quasiquoted list?

查看:83
本文介绍了为什么在准引用列表的末尾可以对非列表使用取消引用拆分?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

准引用列表`(1,@ 2 3)无效,因为2不是列表.但是,`(1 2,@ 3)是有效的,并且会返回一个点分列表:(1 2.3).我在Common Lisp和Scheme中观察到了这个结果.为什么在准引用列表的末尾可以对非列表使用unquote-splicing?为什么结果是虚线列表?

The quasiquoted list `(1 ,@2 3) is invalid because 2 is not a list. However, `(1 2 ,@3) is valid and will return a dotted list: (1 2 . 3). I observe this result in Common Lisp and Scheme. Why is it possible to use unquote-splicing for non-lists at the end of a quasiquoted list? Why is the result a dotted list?

推荐答案

表达式`(1 2,@ 3)在Scheme或Common Lisp中均无效.

The expression `(1 2 ,@3) is not valid in either Scheme or Common Lisp.

在R6RS方案(和R5RS类似)中,未针对使用 unquote-splicing 的非列表操作指定行为.R6RS计划标准要求( 11.17准引用):

In R6RS Scheme (and similarly for R5RS), the behavior is not specified for operating on a non-list with unquote-splicing. The R6RS Scheme Standard requires (11.17 Quasiquotation):

如果在< qq内出现((unquote-splicing< expression> ...)形式)模板",则< expression> s必须计算为列表....

If an (unquote-splicing <expression> ...) form appears inside a <qq template>, then the <expression>s must evaluate to lists....


常见的Lisp

Common Lisp HyperSpec首先说,( 2.4.6反引号):

如果逗号后紧跟一个-符号,则 form 根据符号进行评估,以生成对象列表.然后将这些对象拼接"起来.放在模板中.

If a comma is immediately followed by an at-sign, then the form following the at-sign is evaluated to produce a list of objects. These objects are then "spliced" into place in the template.

在子表达式,@ 3 中, 3 不会求值到列表.这似乎是一个很强的论点,认为该表达式无效.即使在拼接之前将 3 神奇地放置在列表中,这也不会导致点缀列表.HyperSpec继续提供反引号语法的正式摘要.感兴趣的部分是:

In the sub-expression ,@3, 3 does not evaluate to a list. This seems a pretty strong argument that the expression is not valid. Even if the 3 were magically placed in a list before splicing, this would not result in a dotted list. The HyperSpec goes on to provide a formal summary of backquote syntax. The part of interest is:

  • `(x1 x2 x3 ... xn .atom)可能被解释为是

  • `(x1 x2 x3 ... xn . atom) may be interpreted to mean

(附加[x1] [x2] [x3] ... [xn](引用原子))

(append [ x1] [ x2] [ x3] ... [ xn] (quote atom))

其中的括号用于指示xj的转换,如下所示:

where the brackets are used to indicate a transformation of an xj as follows:

-[form]被解释为(list`form),其中包含一个带反引号的格式,然后必须进一步对其进行解释.

-- [form] is interpreted as (list `form), which contains a backquoted form that must then be further interpreted.

-[,form]被解释为(列表形式).

-- [,form] is interpreted as (list form).

-[,@ form]被解释为表单.

-- [,@form] is interpreted as form.

因此在Common Lisp中,原始表达式与`(1 2,@ 3.nil)等效,可以解释为:

So in Common Lisp the original expression, which is equivalent to `(1 2 ,@3 . nil), can be interpreted as:

(append (list `1) (list `2) 3 (quote nil))

但是,这不是对 append 的有效调用,该调用需要除最后一个参数以外的所有参数的正确列表.因此,似乎不支持原始表达式有效的想法.

But, this is not a valid call to append, which requires proper lists for all arguments except the last one. So, there seems to be no support for the idea that the original expression was valid.

它在Scheme和Common Lisp中均可用于OP的事实可能归结为跨不同实现的反引号宏的相似定义.这些定义似乎都希望,@ 之后的形式将求值为一个列表.如果不是这种情况,根据标准,就不能依靠观察到的行为(虚线列表的产生).也就是说,我测试了Chez方案,Guile方案,MIT方案,SBCL,CCL和CLisp:它们都表现出OP报告的相同行为.

The fact that it worked for the OP in both Scheme and Common Lisp probably comes down to similar definitions for the backquote macro across different implementations. These definitions all seem to expect that the form following ,@ will evaluate to a list; when that is not the case, the observed behavior (production of a dotted list) can't be relied upon, according to the standard. That said, I tested Chez Scheme, Guile Scheme, MIT Scheme, SBCL, CCL, and CLisp: all of them exhibited the same behavior reported by OP.

我还针对反引用宏,由盖伊·斯蒂尔(Guy Steele)发布,并发布在CLTL2 中.这种情况更有趣.CLTL2中的此反引号实现旨在探索反引号表达式的行为,并具有可选的代码简化阶段.在这里, $ 对应于反引号,而%@ 对应于,@ .在不简化代码的情况下,扩展原始表达式的结果是:

I also tested against an implementation of the backquote macro by Guy Steele and published in CLTL2. This case is more interesting. This backquote implementation in CLTL2 is meant for exploring the behavior of backquote expressions and has an optional code simplification phase. Here $ corresponds to a backquote, and %@ corresponds to ,@. Without code simplification, the result of expanding the original expression is:

CL-USER> (setf *bq-simplify* nil)
NIL
CL-USER> (try '("$(1 2 %@3)"))
`(1 2 ,@3) = (APPEND (LIST '1) (LIST '2) 3 'NIL)

这对应于上面通过阅读HyperSpec中的描述所期望的表达式.但是请注意,此表达式将无法编译:

This corresponds to the expression which was expected above from reading the description in the HyperSpec. But note that this expression will not compile:

CL-USER> (append (list 1) (list 2) 3 nil)

The value
  3
is not of type
  LIST
[Condition of type TYPE-ERROR]

但是,当启用代码简化功能时:

But, when code simplification is turned on:

CL-USER> (setf *bq-simplify* t)
T
CL-USER> (try '("$(1 2 %@3)"))
`(1 2 ,@3) = (LIST* '1 '2 3)

此简化"字样表达式有效,并计算为点分列表:

This "simplified" expression is valid, and evaluates to a dotted list:

CL-USER> (list* 1 2 3)
(1 2 . 3)

我的结论是,根据Common Lisp标准,,@ 之后的表达式必须是一个列表,但是某些常见的实现要么执行某种形式的代码简化,类似于在CLTL2中显示,或者以某种方式扩展反引号形式,使它出现,从而使非列表形式可以遵循,@ .不要依赖于此,因为很难说什么时候不起作用.

My conclusion is that the expression following ,@ must be a list per the Common Lisp standard, but some common implementations either do some form of code simplification similar to what is shown in CLTL2 or otherwise expand the backquote form in such a way that it appears that a non-list form can follow ,@. Don't rely on this, as it is difficult to say when it won't work.

这篇关于为什么在准引用列表的末尾可以对非列表使用取消引用拆分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆