Reputation: 3848
This question is about sbcl -- or so I thought originally. The question: When is a character not a character? Consider the following code:
(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)
As expected, it produces:
STANDARD-CHAR
STANDARD-CHAR
STANDARD-CHAR
STANDARD-CHAR
Now consider this code:
(defun st (the-string)
(string-trim '(#\Newline #\Space) the-string))
(princ "\"")
(princ (st " abcdefgh "))
(princ "\"")
(terpri)
It produces:
"abcdefgh"
But consider this code:
(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)
When you load it using sbcl, it gives you:
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]
At first, I was anticipating being able to report that clisp does the appropriate call to #'string-trim
, with the anticipated returned value, or maybe errors out. But it does neither of these. The function returns the same string that was passed to it, without any trimming.
Is this what should be happening? What am I missing?
EDIT approx. 2017-10-21 08:50 UTC
The fine answer by PuercoPop inspires a follow-up question. If I should post this as a separate question, just give the word and I will.
Why is it that (at least with sbcl and clisp) this:
(defconstant +asc-lf+ #\Newline)
(defconstant +asc-space+ #\Space)
(prin1 (type-of (first (list #\Newline #\Space))))
(terpri)
(prin1 (type-of (first '(#\Newline #\Space))))
(terpri)
yields this?
STANDARD-CHAR
STANDARD-CHAR
With PuercoPop's answer, I would have expected it to yield something about a symbol, not a character, for the second expression.
Upvotes: 0
Views: 553
Reputation: 139251
The main confusion comes from
(+ a b)
is code, here a function call. Both (quote (+ a b))
and '(+ a b)
is data, as they evaluate to the quoted literal data.#\newline
is already read as a character object. It is built-in syntax: Sharpsign Backslash It is not a string, not a symbol and not some yet unknown piece of data. It is read as an object of type character (I use the wording character object for that here, one could also just say character).These are symbols:
foo
bar
+foo+
*the-foo*
When symbols get evaluated, they evaluate to their value.
These are character objects:
#\f
#\O
#\o
#\newline
When character objects get evaluated, they evaluate to themselves.
Thus '#\foo
, (quote #\foo)
and #\foo
evaluate all to the same object.
These are lists
(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
What happens if we evaluate lists:
(+ 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
Evaluating backquoted lists:
`(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
Your error:
'(+asc-lf+ +asc-space+)
evaluates to a list of symbols.
The function STRING-TRIM
expects a sequence of characters.
You need to write something like this:
(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
Also:
(list #\Newline #\Space)
and '(#\Newline #\Space)
evaluate both to a list of characters. The #\
syntax is a built-in feature of the Lisp reader to construct character objects. Thus #\newline
is converted at read-time into a character-object:
CL-USER 82 > (describe (read))
#\Newline ; we type the nine characters #\Newline
#\Newline is a CHARACTER
Name "Newline"
Code 10
Upvotes: 8
Reputation: 6807
The problem is that you are quoting the "character list". So instead of a list of characters it is a list of symbols. That is
(defun st (the-string)
(string-trim (list +asc-lf+ +asc-space+) the-string))
The error message hints at this when it says
The value +ASC-LF+ is not of type CHARACTER
and not
The value #\Newline is not of type CHARACTER
Upvotes: 5