Clisp 错误消息:对象不能以#\) 开头。这是什么意思?
Clisp error message: an object cannot start with #\). What does this mean?
请看这个例子。我正在使用 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
.
您在 'henry
之后的额外引号字符是另一个对象的开始,这在以下上下文中有意义:
(defparameter *pudding-eater* 'henry '(a b c))
(如果 defparameter 有那么多参数的话)
但是,您引述后的下一个字符是 close-paren。用于显示字符(而不是符号、字符串等)的 Common Lisp 表示法是 #\
前缀,后跟字符。
因此,错误消息并未说明 \
或 #
字符,仅说明 )
,它告诉您您有一个需要更多表达式而不是当前表达式的末尾(因为您通过添加 '
字符开始表达式)。
正如其他答案所指出的,#\(
是表示 (
字符的语法。请参阅 2.4.8 Sharpsign 部分。首先 reader 看到 #
,然后调度下一个字符,\
(反斜杠)用于读取字符对象。因此,您的错误消息是说 )
在您的输入中是意外的。
错误信息
I was expecting some error message like umatched parenthesis.
这基本上就是错误的意思,SBCL 等其他实现会产生您期望的消息。我在 Emacs 中工作:
CL-USER> )
... 使用 unmatched close parenthesis
和回溯进入调试器。
让我们看看为什么。使用 GET-MACRO-CHARACTER
,我们要求我们的 Common Lisp 实现 return 与 #\)
字符关联的函数:
CL-USER> (get-macro-character #\))
SB-IMPL::READ-RIGHT-PAREN
NIL
在 Emacs 中,结果值显示为 表示,这使我们可以检查它。您还可以指向函数的名称,如果您的 SBCL 安装允许它(例如,您从源安装),您可以使用 M-.:[=37 转到定义=]
(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
不过那个系统函数的源码定义不是很清楚(如果你好奇的话可以看non-official mirror),但是显示另一个错误信息也就不足为奇了。
read-table 以及 Lisp 如何读取表达式列表
行为取决于当前 readtable 中哪些函数绑定到正在读取的字符。
在这种情况下,所有实现都会发出错误信号,因为当您到达必须在可读表中查找右括号的位置时,输入的格式肯定很糟糕。这是像 READ-DELIMITED-LIST
这样的函数的工作,从与 左括号 、a.k.a 关联的函数调用。 #\(
,一直读到找到对应的右括号为止。 请注意,如果您在 SBCL 中 look-up reader for #\(
,它不会使用 read-delimited-list
,而是使用不同的专用版本。 post这里有点太长了.
报价和递归阅读
在你的情况下,你也有报价。报价如何表现?
(defun read-quote (stream ignore)
(declare (ignore ignore))
(list 'quote (read stream t nil t)))
它构建一个以quote
开头并包含通过递归调用READ
获得的sub-expression 的列表。这与上面一样,当我在 REPL 提示符下输入右括号时。由于我们当前不在左括号的上下文中,我们遇到 #\)
字符,在可读表中查找它并发出错误信号。
你写
'henry')
'
是 Common Lisp 中的终止宏字符。
终止表示:
if it appears while parsing a token, it terminates that token.
所以第二个引号字符终止了之前的标记,这里是henry
。
我们有:quote, henry, quote, 右括号。
引用字符是一个宏字符,它专门导致另一个对象被读取。 'some-object
读作 (QUOTE some-object)
。 some-object
可以是任何数据:数字、字符串、列表、符号...
因此正在读取一个新对象,并且对象的文本表示不能以右括号开头。右括号用于结束列表或 cons 单元格。
如果您想在符号中使用右括号,则需要将其转义:
CL-USER 3 > '\)
\)
CL-USER 4 > '|)|
\)
CL-USER 5 > '|)woaaah(|
|)woaaah(|
请看这个例子。我正在使用 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
.
您在 'henry
之后的额外引号字符是另一个对象的开始,这在以下上下文中有意义:
(defparameter *pudding-eater* 'henry '(a b c))
(如果 defparameter 有那么多参数的话)
但是,您引述后的下一个字符是 close-paren。用于显示字符(而不是符号、字符串等)的 Common Lisp 表示法是 #\
前缀,后跟字符。
因此,错误消息并未说明 \
或 #
字符,仅说明 )
,它告诉您您有一个需要更多表达式而不是当前表达式的末尾(因为您通过添加 '
字符开始表达式)。
正如其他答案所指出的,#\(
是表示 (
字符的语法。请参阅 2.4.8 Sharpsign 部分。首先 reader 看到 #
,然后调度下一个字符,\
(反斜杠)用于读取字符对象。因此,您的错误消息是说 )
在您的输入中是意外的。
错误信息
I was expecting some error message like umatched parenthesis.
这基本上就是错误的意思,SBCL 等其他实现会产生您期望的消息。我在 Emacs 中工作:
CL-USER> )
... 使用 unmatched close parenthesis
和回溯进入调试器。
让我们看看为什么。使用 GET-MACRO-CHARACTER
,我们要求我们的 Common Lisp 实现 return 与 #\)
字符关联的函数:
CL-USER> (get-macro-character #\))
SB-IMPL::READ-RIGHT-PAREN
NIL
在 Emacs 中,结果值显示为 表示,这使我们可以检查它。您还可以指向函数的名称,如果您的 SBCL 安装允许它(例如,您从源安装),您可以使用 M-.:[=37 转到定义=]
(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
不过那个系统函数的源码定义不是很清楚(如果你好奇的话可以看non-official mirror),但是显示另一个错误信息也就不足为奇了。
read-table 以及 Lisp 如何读取表达式列表
行为取决于当前 readtable 中哪些函数绑定到正在读取的字符。
在这种情况下,所有实现都会发出错误信号,因为当您到达必须在可读表中查找右括号的位置时,输入的格式肯定很糟糕。这是像 READ-DELIMITED-LIST
这样的函数的工作,从与 左括号 、a.k.a 关联的函数调用。 #\(
,一直读到找到对应的右括号为止。 请注意,如果您在 SBCL 中 look-up reader for #\(
,它不会使用 read-delimited-list
,而是使用不同的专用版本。 post这里有点太长了.
报价和递归阅读
在你的情况下,你也有报价。报价如何表现?
(defun read-quote (stream ignore)
(declare (ignore ignore))
(list 'quote (read stream t nil t)))
它构建一个以quote
开头并包含通过递归调用READ
获得的sub-expression 的列表。这与上面一样,当我在 REPL 提示符下输入右括号时。由于我们当前不在左括号的上下文中,我们遇到 #\)
字符,在可读表中查找它并发出错误信号。
你写
'henry')
'
是 Common Lisp 中的终止宏字符。
终止表示:
if it appears while parsing a token, it terminates that token.
所以第二个引号字符终止了之前的标记,这里是henry
。
我们有:quote, henry, quote, 右括号。
引用字符是一个宏字符,它专门导致另一个对象被读取。 'some-object
读作 (QUOTE some-object)
。 some-object
可以是任何数据:数字、字符串、列表、符号...
因此正在读取一个新对象,并且对象的文本表示不能以右括号开头。右括号用于结束列表或 cons 单元格。
如果您想在符号中使用右括号,则需要将其转义:
CL-USER 3 > '\)
\)
CL-USER 4 > '|)|
\)
CL-USER 5 > '|)woaaah(|
|)woaaah(|