2

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.

sai
  • 55
  • 5

1 Answers1

1

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
Alex Knauth
  • 8,133
  • 2
  • 16
  • 31