sbcl (and clisp): When is a character not a character? (using defconstant) - lisp

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.

The main confusion comes from
the dual purpose of lists: data and code. For evaluation (+ 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.
reading already creates objects. #\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

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

Related

What is the difference between #\ , ' and #'?

In Common Lisp, given that "a" is simply a character, what is the difference between #\a, 'a #'a?
My question comes from the tutorialspoint.com tutorial on Lisp. At one point the tutorial introduces:
; a character array with all initial elements set to a
; is a string actually
(write(make-array 10 :element-type 'character :initial-element #\a))
(terpri)
; a two dimensional array with initial values a
(setq myarray (make-array '(2 2) :initial-element 'a :adjustable t))
(write myarray)
(terpri)
With the output:
"aaaaaaaaaa"
#2A((A A) (A A))
#' is not included in this example but I'm including it in the question because it can be confusing as well. 🙂
Thank you very much! 😊
To start, a is not "simply a character." The Lisp reader parses #\a as the character literal a, which is an object in Common Lisp. Note that #\a and #\A are different character objects.
When the Lisp reader encounters a single quote, the expression following the single quote is not evaluated. Specifically, 'a is treated as (quote a), where quote returns its argument unevaluated. Now, a is a symbol, so 'a evaluates to that symbol. But the Lisp reader upcases most characters it reads by default, so 'a really evaluates to the symbol A. The good news is that whether you type a or A, the Lisp reader will read A (unless you mess with the readtable), and both 'a and 'A evaluate to the symbol A.
When the Lisp reader encounters #'a, the entire expression is treated as (function a), which when evaluated returns the function associated with the name a. But, note that it is an error to use function, and by extension #', on an identifier that does not denote a function.
To clarify this last part a bit, consider the following REPL interaction:
CL-USER> (defvar a 1)
A
CL-USER> a
1
CL-USER> #'a
The function COMMON-LISP-USER::A is undefined.
[Condition of type UNDEFINED-FUNCTION]
Here the variable a is defined and given the value 1, but when we try to access the function denoted by a we get an error message because there is no such function. Continuing:
; Evaluation aborted on #<UNDEFINED-FUNCTION A {1002DDC303}>.
CL-USER> (defun a (x) x)
A
CL-USER> (a 'b)
B
CL-USER> a
1
CL-USER> #'a
#<FUNCTION A>
Now we have defined a function named a that simply returns its argument. You can see that when we call a with an argument 'b we get the expected result: (a 'b) --> b. But, then when we evaluate a alone we still get 1. Symbols in Common Lisp are objects that have, among other cells, value cells and function cells. After the above interaction, the symbol a now has 1 in its value cell, and it has the function we have defined in its function cell. When the symbol a is evaluated the value cell is accessed, but when (function a) or #'a is evaluated, the function cell is accessed. You can see above that when #'a is evaluated, the function we defined is returned, and the REPL prints #<FUNCTION A> to show this.
As an aside, I wouldn't recommend using Tutorialspoint to learn Common Lisp. Glancing over the site, right away I see this:
LISP expressions are case-insensitive, cos 45 or COS 45 are same.
This is just wrong. And, Lisp is not written in all-caps. None of this inspires faith. Instead, find a good book. There are some recommendations on the common-lisp tag-info page.
#\
This is to introduce a character.
CL-USER> #\a
#\a
CL-USER> (character 'a)
#\A
CL-USER> (character "a")
#\a
'
This is quote, to quote and not evaluate things and construct object literals.
CL-USER> a
=> error: the variable a is unbound.
CL-USER> 'a
A
CL-USER> (inspect 'a)
The object is a SYMBOL.
0. Name: "A"
1. Package: #<PACKAGE "COMMON-LISP-USER">
2. Value: "unbound"
3. Function: "unbound"
4. Plist: NIL
> q
CL-USER> (equal (list 1 2) (quote (1 2))) ;; aka '(1 2)
T ;; but watch out with object literals constructed with quote, prefer constructor functions.
and #'
This is sharpsign-quote to reference a function.
CL-USER> #'a
=> error: The function COMMON-LISP-USER::A is undefined.
CL-USER> (defun a () (print "hello A"))
A
CL-USER> (a)
"hello A"
"hello A"
CL-USER> #'a
#<FUNCTION A>
CL-USER> (function a)
#<FUNCTION A>
One can ask Lisp to describe the data objects you've mentioned.
If we look at the expressions:
CL-USER 13 > (dolist (object (list '#\a ''a '#'a))
(terpri)
(describe object)
(terpri))
#\a is a CHARACTER
Name "Latin-Small-Letter-A"
Code 97
(QUOTE A) is a LIST
0 QUOTE
1 A
(FUNCTION A) is a LIST
0 FUNCTION
1 A
NIL
If we look at the evaluated expressions:
CL-USER 5 > (dolist (object (list #\a 'a #'a))
(terpri)
(describe object)
(terpri))
#\a is a CHARACTER
Name "Latin-Small-Letter-A"
Code 97
A is a SYMBOL
NAME "A"
VALUE #<unbound value>
FUNCTION #<interpreted function A 422005BD54>
PLIST NIL
PACKAGE #<The COMMON-LISP-USER package, 73/256 internal, 0/4 external>
#<interpreted function A 422005BD54> is a TYPE::INTERPRETED-FUNCTION
CODE (LAMBDA (B)
A)

For-each loop over pairs in Racket

I'm trying to print a list of pairs of values (representing key/value pairs) in Racket.
Here's the code I have right now:
#lang racket
(define (write-json keyvalues)
(displayln "{")
(for-each
(lambda (kv) (
(displayln (format "~a: ~a," (car kv) (cdr kv)))))
keyvalues)
(displayln "}"))
(write-json (list (cons "a" 1) (cons "b" 2)))
When I run the example, it prints:
{
a: 1,
Then, it crashes with this error message:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...: [none]
context...:
/.../racket/collects/racket/private/map.rkt:58:19: loop
"test.rkt": [running body]
for-loop
run-module-instance!125
perform-require!78
Any idea what's going on?
Thanks!
This is a paren issue. You have an extra set of parentheses around your lambda's body, ie:
( (displayln (format "~a: ~a;" (car kv) (cdr kv))) )
Since displayln is used for side effect, its output is void, hence why your error message states that you're trying to run (#<void>).
In general, whenever you get an error stating "expected a procedure that can be applied to arguments", see if you have parentheses issues in your code block. Editors like Dr. Racket would highlight that region for you.

symbols handling: cannot compare for identity

I don't get why
(setq a_sym 'abc)
(print (eq a_sym 'abc))
(print (eq 'x 'x))
(print (eq (first '('x 2 3)) 'x))
prints
T
T
NIL
Why the symbol 'x in the third statement is handled differently than second ? And, down to earth, how to compare them for identity ?
If you trace what you are comparing, you will see your mistake right away:
[1]> (eq (first '('x 2 3)) 'x)
NIL
[2]> (trace eq)
** - Continuable Error
TRACE(EQ): #<PACKAGE COMMON-LISP> is locked
If you continue (by typing 'continue'): Ignore the lock and proceed
The following restarts are also available:
ABORT :R1 Abort main loop
Break 1 [3]> :c
WARNING: TRACE: redefining function EQ in top-level, was defined in C
;; Tracing function EQ.
(EQ)
[4]> (eq (first '('x 2 3)) 'x)
1. Trace: (EQ ''X 'X) ; <======= note 1
1. Trace: EQ ==> NIL
NIL
[5]> (eq (first '(x 2 3)) 'x)
1. Trace: (EQ 'X 'X) ; <======= note 2
1. Trace: EQ ==> T
T
IOW, you are "overquoting" your x: when you type 'x, it's the same as (quote x) so, you are checking for equality of symbol x and list (quote x) and, of course, getting nil.
Notes:
(eq ''x 'x): since eq is a function, its arguments are evaluated and we are comparing 'x == (quote x) with x and getting nil.
(eq 'x 'x): for the same reason, we are comparing x with x and getting t.
Related:
Lisp quote work internally
Confused by Lisp Quoting
When to use 'quote in Lisp
Lisp: quoting a list of symbols' values
Syntax and reading
You wrote:
symbol 'x
Note that 'x is not a symbol. It's a quote character in front of a symbol. The quote character has a special meaning in s-expressions: read the next item and enclose it in (quote ...).
Thus 'x is really the list (quote x).
CL-USER 9 > (read-from-string "'x")
(QUOTE X)
2
Evaluation
A quoted object is not evaluated. The quote is a special operator, which means it is built-in syntax/semantics in Common Lisp and not a function and not a macro. The evaluator returns the quoted object as such:
CL-USER 10 > (quote x)
X
Your example
(eq (first (quote ((quote x) 2 3))) (quote x))
Let's evaluate the first part:
CL-USER 13 > (first (quote ((quote x) 2 3)))
(QUOTE X)
The result is the list (quote x).
Let's evaluate the second part:
CL-USER 14 > 'x
X
So the result is the symbol x.
x and (quote x) are not eq.
Evaluation and Quoting
'('x 2 3)
What would be the purpose of the second quote in the list?
The first quote already means that the WHOLE following data structure is not to be evaluated. Thus it is not necessary to quote a symbol inside to prevent its evaluation. If a list is quoted, none of its sublists or subelements are evaluated.
Summary
The quote is not part of the symbol. It is a built-in special operator used to prevent evaluation.

Can a Lisp read procedure read this and how?

I'm writing a grammar which I intend to implement in a Lisp read procedure, i.e. reading one expression at a time from an input source which is i.e. mutable. Most of the grammar is just like Lisp, but the two pertinent changes are:
Whitespace is read and is part of the resulting syntax. Contiguous whitespace is grouped together like contiguous non-whitespace characters are grouped as identifiers, and the result of reading such a string is a "whitespace object", which stores the exact sequence of characters read. The evaluator ignores whitespace objects when they appear in a list (in other words, if foo is a whitespace object then (eval '(+ 3 foo 4)) is equivalent to (eval '(+ 3 4))), and if it is asked to evaluate one directly, it is self-evaluating.
Secondly, if several tokens other than whitespace tokens appear on the same line, those tokens are collected into a list and that list is the result of the read.
e.g.,
+ 3 4 5
(+ 3 4 5)
+ 3 4 (+ 1 4)
(+ 3 4 (+ 1 4))
all produce the value 12.
Is it possible to implement this reader as a Lisp read procedure that follows the typical expectations of a read procedure? If so, how? (I'm at a loss.)
Edit: Clarification on whitespace:
If we say that a "whitespace object" is simply a string and read, then reading the following segment:
(foo bar baz)
produces a syntax object like:
'(foo " " bar " " baz)
In other words, the whitespace between tokens is stored in the resultant syntax object.
Suppose I write a macro named ->, which takes a syntax object (scheme style macro), and whitespace? is a predicate identifying whitespace syntax objects
(define-macro (-> stx)
(let* ((stxl (syntax-object->list stx))
(obj (car stxl))
(let proc ((res empty))
(lst (cdr stxl)))
(let ((method (car lst)))
(if (whitespace? method)
; skip whitespace, recur immediately
(proc res (cdr lst))
; Insert obj as the second element in method
(let ((modified-method (cons (car method)
(cons obj (cdr method)))))
; recur
(proc (cons res modified-method) (cdr lst))))))))
The reading part of this is pretty easy. You just need a whitespace test, and then your reading function will install a custom reader character macro that detects whitespace and reads consecutive sequences of whitespace into a single object. First, the whitespace test and a whitespace object; these are pretty simple:
(defparameter *whitespace*
#(#\space #\tab #\return #\newline)
"A vector of whitespace characters.")
(defun whitespace-p (char)
"Returns true if CHAR is in *WHITESPACE*."
(find char *whitespace* :test 'char=))
(defstruct whitespace-object
characters)
Now the macro character function:
(defun whitespace-macro-char (stream char)
"A macro character function that consumes characters from
stream (including CHAR), until a non-whitespace character (or end of
file) is encountered. Returns a whitespace-object whose characters
slot contains a string of the whitespace characters."
(let ((chars (loop for c = (peek-char nil stream nil #\a)
while (whitespace-p c)
collect (read-char stream))))
(make-whitespace-object
:characters (coerce (list* char chars) 'string))))
Now the read function just has the same signature as the normal read, but copies the readtable, then installs the macro function, and calls read. The result from read is returned, and the readtable is restored:
(defun xread (&optional (stream *standard-input*) (eof-error-p t) eof-value recursive-p)
"Like READ, but called with *READTABLE* bound to a readtable in
which each whitespace characters (that is, each character in
*WHITESPACE*) is a macro characters whose macro function is
WHITESPACE-MACRO-CHAR."
(let ((rt (copy-readtable)))
(map nil (lambda (wchar)
(set-macro-character wchar #'whitespace-macro-char))
*whitespace*)
(unwind-protect (read stream eof-error-p eof-value recursive-p)
(setf *readtable* rt))))
Example:
(with-input-from-string (in "(+ 1 2 (* 3
4))")
(xread in))
(+ #S(WHITESPACE-OBJECT :CHARACTERS " ") 1
#S(WHITESPACE-OBJECT :CHARACTERS " ") 2
#S(WHITESPACE-OBJECT :CHARACTERS " ")
(* #S(WHITESPACE-OBJECT :CHARACTERS " ") 3
#S(WHITESPACE-OBJECT
:CHARACTERS "
")
4))
Now, to implement the eval counterpart that you want, you need to be able to remove whitespace objects from lists. This isn't too hard, and we can write a slightly more general utility function to do it for us:
(defun remove-element-if (predicate tree)
"Returns a new tree like TREE, but which contains no elements in an
element position which ssatisfy PREDICATE. An element is in element
position if it is the car of some cons cell in TREE."
(if (not (consp tree))
tree
(if (funcall predicate (car tree))
(remove-element-if predicate (cdr tree))
(cons (remove-element-if predicate (car tree))
(remove-element-if predicate (cdr tree))))))
CL-USER> (remove-element-if (lambda (x) (and (numberp x) (evenp x))) '(+ 1 2 3 4))
(+ 1 3)
CL-USER> (with-input-from-string (in "(+ 1 2 (* 3
4))")
(remove-element-if 'whitespace-object-p (xread in)))
(+ 1 2 (* 3 4))
So now the evaluation function is a simple wrapper around eval:
(defun xeval (form)
(eval (remove-element-if 'whitespace-object-p form)))
CL-USER> (with-input-from-string (in "(+ 1 2 (* 3
4))")
(xeval (xread in)))
15
Let's make sure that standalone whitespace objects still appear as expected:
CL-USER> (with-input-from-string (in " ")
(let* ((exp (xread in))
(val (xeval exp)))
(values exp val)))
#S(WHITESPACE-OBJECT :CHARACTERS " ")
#S(WHITESPACE-OBJECT :CHARACTERS " ")

String to list without #\ in common lisp

I'd like to turn String into lists. For example, http => (h t t p).
I try:
(defun string-to-list (s)
(assert (stringp s) (s) "~s :questa non e una stringa")
(coerce s 'list))
but if I do
(string-to-list "http")
results:
(#\h #\t #\t #\p).
Can I remove #\ ?
thanks in advance :)
Why would you do that? What you ask is to split a string (a one-dimensional array of characters) into a list of symbols. Do you really want that?
#\h is a character object printed.
You can print them differently:
CL-USER 8 > (princ #\h)
h
CL-USER 9 > (prin1 #\h)
#\h
Let's print the list using PRINC:
CL-USER 10 > (map nil #'princ (coerce "Hello!" 'list))
Hello!
Btw., since strings, vectors and lists are sequences, you can MAP directly over the string...
CL-USER 11 > (map nil #'princ "Hello!")
Hello!
You can turn a string into a symbol with intern. You can turn a character into a string with string. Interning a lower-case string might cause it to be printed as |h| instead of h, so you'll want to string-upcase it. Putting all that together gives:
(loop for c in (coerce "http" 'list)
collecting (intern (string-upcase (string c))))
Expanding upon larsmans' answer, you can print lowercase symbols unquoted if you change the readtable:
(let ((*readtable* (copy-readtable)))
(setf (readtable-case *readtable*) :preserve)
(prin1 (loop for c in (coerce "http" 'list)
collecting (intern (string c)))))
This will print (h t t p) and return (|h| |t| |t| |p|).
You can print characters unescaped. See the variable *PRINT-ESCAPE*.
The function WRITE has a keyword parameter :ESCAPE for that:
(defun string-to-list (s)
(assert (stringp s) (s) "~s :questa non e una stringa")
(write (coerce s 'list) :escape nil)
CL-USER 11 > (string-to-list "abcd")
(a b c d)
(#\a #\b #\c #\d)
In above example the first form is printed by calling WRITE and the second form is the return value printed by the REPL.