sbcl(和clisp):什么时候字符不是字符? (使用defconstant)

时间:2017-10-21 03:41:11

标签: lisp common-lisp sbcl clisp

这个问题是关于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 的答案,我原本期望它会为第二个表达式产生关于符号而不是字符的东西。

2 个答案:

答案 0 :(得分:8)

主要的困惑来自

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

    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
    

答案 1 :(得分:5)

问题是你引用了#34;字符列表"。因此,它不是字符列表,而是符号列表。那是

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

当错误消息显示

时,会显示错误消息
  

价值       + ASC-LF +不是类型       CHARACTER

而不是

  

价值       #\换行符不是类型       CHARACTER