请看这个例子。我正在使用GNU CLISP 2.49。
(defparameter *pudding-eater* 'henry')
;; output:
READ from
#<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM> #<IO TERMINAL-STREAM>>: an
object cannot start with #\)
(defparameter *pudding-eater* 'henry)
;; output:
*PUDDING-EATER*
我明白这是造成问题的双引号。我所做的不明白,an object cannot start with #\)
是什么意思?我从哪里开始#\)
?我期待一些错误消息,如umatched parenthesis
。
答案 0 :(得分:4)
'henry
之后的额外引号字符是另一个对象的开头,这在以下情况下是有意义的:
(defparameter *pudding-eater* 'henry '(a b c))
(如果defparameter采取了那么多论点,无论如何)
但是,你引用之后的下一个字符就是密切关注。用于显示字符(而不是符号,字符串等)的Common Lisp表示法是#\
前缀,后跟字符。
因此,错误消息没有说明\
或#
字符,只有)
,而且它告诉您有一个预期更多表达式而不是结束的字符当前的一个(因为你通过添加'
字符来启动表达式。)
答案 1 :(得分:3)
正如其他答案所指出的,#\(
是表示(
字符的语法。见2.4.8 Sharpsign部分。首先,读者看到#
,然后调度下一个字符\
(反斜杠),用于读取字符对象。因此,您的错误消息表明您的输入中)
意外。
我期待一些错误消息,比如umatched括号。
这基本上就是错误所说的,而像SBCL这样的其他实现会产生您期望的消息。我在Emacs工作:
CL-USER> )
...使用unmatched close parenthesis
和回溯进入调试器。
让我们看看为什么。使用GET-MACRO-CHARACTER
,我们要求Common Lisp实现返回与#\)
字符关联的函数:
CL-USER> (get-macro-character #\))
SB-IMPL::READ-RIGHT-PAREN
NIL
在Emacs中,结果值显示为演示文稿,它允许我们检查它。您也可以指出该函数的名称,如果您的SBCL安装允许它(例如,您从源代码安装),您可以使用 M - 。:
进入定义。(defun read-right-paren (stream ignore)
(declare (ignore ignore))
(simple-reader-error stream "unmatched close parenthesis"))
与CLISP相同会产生您看到的错误。我们也可以这样做:
CL-USER> (get-macro-character #\))
#<SYSTEM-FUNCTION SYSTEM::RPAR-READER>
NIL
然而,该系统功能的源定义并不是那么清晰(如果您好奇,请参阅非官方mirror),但显示另一条错误消息并不奇怪。
行为取决于当前readtable中哪些函数绑定到正在读取的字符。
在这种情况下,所有实现都会发出错误信号,因为当您到达必须查找右括号的可读表的点时,输入必然是错误的。这是READ-DELIMITED-LIST
之类函数的作用,从与左括号相关联的函数调用,a.k.a。#\(
,直到找到相应的右括号为止。 请注意,如果您在SBCL中查找了#\(
的阅读器,则它不会使用read-delimited-list
,而是使用不同的专用版本。在这里发布它有点太长了。
在您的情况下,您也有报价。引用如何表现?
(defun read-quote (stream ignore)
(declare (ignore ignore))
(list 'quote (read stream t nil t)))
它构建一个以quote
开头并包含通过递归调用READ
获得的子表达式的列表。当我在REPL提示符下输入右括号时,就像上面一样。由于我们目前不在开括号的上下文中,因此我们会遇到#\)
字符,在readtable中查找并发出错误信号。
答案 2 :(得分:2)
你写
'henry')
'
是Common Lisp中的终止宏字符。
终止意味着:
如果在解析令牌时出现,它会终止该令牌。
所以第二个引号字符在此之前终止了令牌henry
。
我们有:引用,亨利,引用,右括号。
引号字符是<em>宏字符,它特意导致另一个对象被读取。 'some-object
被视为(QUOTE some-object)
。 some-object
可以是任何数据:数字,字符串,列表,符号......
因此正在读取新对象,并且对象的文本表示不能以闭括号开头。封闭括号用于结束列表或缺陷单元。
如果您想在符号中使用右括号,则需要将其转义:
CL-USER 3 > '\)
\)
CL-USER 4 > '|)|
\)
CL-USER 5 > '|)woaaah(|
|)woaaah(|