【问题标题】:sbcl (and clisp): When is a character not a character? (using defconstant)sbcl(和 clisp):什么时候一个字符不是字符? (使用默认常量)
【发布时间】:2017-10-21 03:41:10
【问题描述】:

这个问题是关于 sbcl 的——至少我最初是这么想的。问题:什么时候一个角色不是一个角色?考虑以下代码:

(defconstant +asc-lf+    #\Newline)
(defconstant +asc-space+ #\Space)
(prin1 (type-of #\Newline  )) (terpri)
(prin1 (type-of #\Space    )) (terpri)
(prin1 (type-of +asc-lf+   )) (terpri)
(prin1 (type-of +asc-space+)) (terpri)

正如预期的那样,它会产生:

STANDARD-CHAR
STANDARD-CHAR
STANDARD-CHAR
STANDARD-CHAR

现在考虑这段代码:

(defun st (the-string)
  (string-trim '(#\Newline #\Space) the-string))
(princ "\"")
(princ (st "   abcdefgh   "))
(princ "\"")
(terpri)

它产生:

"abcdefgh"

但考虑一下这段代码:

(defconstant +asc-lf+    #\Newline)
(defconstant +asc-space+ #\Space)
(defun st (the-string)
  (string-trim '(+asc-lf+ +asc-space+) the-string))
(princ "\"")
(princ (st "   abcdefgh   "))
(princ "\"")
(terpri)

当您使用 sbcl 加载它时,它会为您提供:

While evaluating the form starting at line 6, column 0
  of #P"/u/home/sbcl/experiments/type-conflict.d/2.lisp":"

debugger invoked on a TYPE-ERROR:
  The value
    +ASC-LF+
  is not of type
    CHARACTER

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY   ] Retry EVAL of current toplevel form.
  1: [CONTINUE] Ignore error and continue loading file "/u/home/sbcl/experiments/type-conflict.d/2.lisp".
  2: [ABORT   ] Abort loading file "/u/home/sbcl/experiments/type-conflict.d/2.lisp".
  3:            Exit debugger, returning to top level.

((FLET SB-IMPL::TRIM-CHAR-P :IN SB-IMPL::GENERIC-STRING-TRIM) #\ )
0] 

起初,我期待能够报告 clisp 对 #'string-trim 进行了适当的调用,并带有预期的返回值,或者可能会出错。但它都不做这些。该函数返回传递给它的相同字符串,没有任何修剪。

这是应该发生的事情吗?我错过了什么?

编辑大约。 2017-10-21 08:50 UTC

PuercoPop 的精彩回答引发了后续问题。如果我应该将此作为一个单独的问题发布,只需说出这个词,我会的。

为什么会这样(至少对于 sbcl 和 clisp):

(defconstant +asc-lf+    #\Newline)
(defconstant +asc-space+ #\Space)
(prin1 (type-of (first (list #\Newline #\Space))))
(terpri)
(prin1 (type-of (first '(#\Newline #\Space))))
(terpri)

会这样吗?

STANDARD-CHAR
STANDARD-CHAR

有了 PuercoPop 的回答,我原以为它会为第二个表达式产生一些关于符号而不是字符的东西。

【问题讨论】:

  • #\Newline 是阅读器语法,它在阅读时构造一个换行符对象。
  • 第二个问题可能对您有所帮助:(type-of (first '(1 2))) 应该是什么?

标签: lisp common-lisp sbcl clisp


【解决方案1】:

主要的困惑来自于

  1. 列表的双重用途:数据和代码。对于评估(+ a b) 是代码,这里是函数调用。 (quote (+ a b))'(+ a b) 都是数据,因为它们评估的是引用的文字数据。
  2. 阅读已经创建了对象。 #\newline 已作为字符对象读取。它是内置语法:Sharpsign Backslash 它不是字符串,不是符号,也不是一些未知的数据。它被解读为字符类型的对象(我在这里使用字符对象的措辞,也可以直接说character)。

这些是符号:

foo
bar
+foo+
*the-foo*

当符号被求值时,它们会求值。

这些是字符对象:

#\f
#\O
#\o
#\newline

当角色对象被评估时,他们评估自己。 因此,'#\foo(quote #\foo)#\foo 将全部计算为同一个对象。

这些是列表

(newline #\newline)   ; the first item is a symbol, the second a character object
(#\a #\b #\c)         ; a list of character objects
(a b c)               ; a list of symbols

如果我们评估列表会发生什么:

(+ a b)               ; the sum of the values of A and B

(list a b)            ; a list gets computed, with the values of variables a and b
(list 'a 'b)          ; a list gets computed, with the symbols A and B

'(a b)                ; a literal list of the symbols A and B
'(#\a #\b)            ; a literal list of the character objects #\a and #\b
'(a #\a)              ; a literal list of the symbol A and the character object #\a

(#\a #\b)            ; an error, #\a is not a function/macro/special-form
(+ a 'b)             ; an error, a symbol B is not a number 

评估反引号列表:

`(a ,a #\a ,#\a)      ; a list of the symbol a, the value of the variable a,
                      ; the character object a and again the character object a

您的错误

'(+asc-lf+ +asc-space+) 计算为符号列表。

函数STRING-TRIM 需要一个字符序列。

你需要这样写:

(list +asc-lf+ +asc-space+)   ; calling the function list
`(,+asc-lf+ ,+asc-space+)     ; a backquoted list with comma for evaluation
(vector +asc-lf+ +asc-space+) ; the constructed vector is also a sequence

还有:

(list #\Newline #\Space)'(#\Newline #\Space) 都计算为字符列表。 #\ 语法是 Lisp reader 的内置功能,用于构造字符对象。因此#\newline 在读取时被转换为字符对象:

CL-USER 82 > (describe (read))
#\Newline                           ; we type the nine characters #\Newline
#\Newline is a CHARACTER
Name      "Newline"
Code      10

【讨论】:

    【解决方案2】:

    问题是您引用了“字符列表”。因此,它不是字符列表,而是符号列表。那是

    (defun st (the-string)
      (string-trim (list +asc-lf+ +asc-space+) the-string))
    

    错误信息提示了这一点

    价值 +ASC-LF+ 不是类型 人物

    而不是

    价值 #\Newline 不是类型 人物

    【讨论】:

    • 您的出色回答确实激发了一个后续问题,我在原始问题的末尾对其进行了编辑。如果我应该将它作为一个单独的问题发布,请告诉我,我很乐意这样做。
    猜你喜欢
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    • 2012-08-20
    • 2010-10-10
    • 2012-12-01
    • 2011-01-04
    • 2019-04-03
    • 2017-12-28
    相关资源
    最近更新 更多