I can't understand this scheme read
function's behavior.
gosh> (null? '())
#t
gosh> (null? (read))
'()
#f
gosh> (define a (read))
'()
a
gosh> a
'()
gosh> (null? a)
#f
I expected (null? (read))
is #t
(true) when I inputted '()
. Not only Gauche, but also MIT-Scheme and GNU/Guile behaves like this.
The read
function doesn't evaluate the text its given, it treats it as an unevaluated expression and returns the expression tree as data. For example:
(read) ;input: (+ 4 5)
Is equivalent to (list '+ 4 5)
:
> (read) ;input: (+ 4 5)
(+ 4 5)
> (list '+ 4 5)
(+ 4 5)
> (equal? (read) (list '+ 4 5)) ;input: (+ 4 5)
#t
From now on I'll use the ;=
syntax to demonstrate how you would write it with constructors like list
.
> (read) ;input: (+ 4 5)
;= (list '+ 4 5)
(+ 4 5)
Now, because read
returns the data representation for the expression its given, it "adds a quote level". By that I mean that to write an equivalent expression, you would have to wrap quote
around it.
> (read) ;input: (+ 4 5)
;= (list '+ 4 5)
;= '(+ 4 5)
> (read) ;input: (quote (+ 4 5))
;= (list 'quote (list '+ 4 5))
;= '(quote (+ 4 5))
;= ''(+ 4 5)
Because read
and write
deal with unevaluated expressions, the read
function will seem to add a quote level, and the write
function will seem to remove a quote level:
> (write '(+ 4 5))
;output: (+ 4 5)
> (write ''(+ 4 5))
;output: '(+ 4 5)
> (write '''''(+ 4 5))
;output: ''''(+ 4 5)
The read
function does the opposite, seeming to add a quote level. However, this is made more obscure by the fact that the Scheme Repl uses write
, which "removes" it again. However, if you concentrate on the ;=
expressions it's more clear why read
and write
are opposites:
> (read) ;input (+ 4 5) (no quotes)
;= '(+ 4 5) (one quote)
(+ 4 5) (the `write` function removes a quote)
> (read) ;input '(+ 4 5) (one quote)
;= ''(+ 4 5) (two quotes)
'(+ 4 5) (the `write` function removes a quote)
> (read) ;input '''(+ 4 5) (three quotes)
;= ''''(+ 4 5) (four quotes)
'''(+ 4 5) (the `write` function removes a quote)
Now back to your example:
> (read) ;input: '()
;= ???
???
Since read
adds a quote to represent an expression as data, reading '()
is equivalent to ''()
.
> (read) ;input: '()
;= ''()
;= (list 'quote (list))
'()
> (define a (read)) ;input: '()
> a
;= ''()
;= (list 'quote (list))
'()
> (equal? a ''())
#t
> (equal? a (list 'quote (list)))
#t
To actually get something equivalent to '()
so that it will be null?
, you have to give ()
as input.
> (read) ;input: ()
;= '()
;= (list)
()
> (define a (read)) ;input: ()
> a
;= '()
;= (list)
()
> (equal? a '())
#t
> (null? a)
#t