Live data from Hacker News

The empty list

tfeb.org

11–20 of 109 posts

Re: The empty list

#11
post #8
post #4

> It is necessary that there be a special empty-list object which is a list but not a cons. That is not true. NIL could be a CONS. In fact, it acts just like a CONS whose CAR and CDR are itself. The only way in which NIL does not behave like a CONS is that it does not answer true to CONSP. But that doesn't matter because it answers true to NULL, so you can build a CL-style CONSP if you want it by checking for (AND (C…

I tend to agree but would be happy to be proven wrong by more knowledgeable folks in these comments. However I assume here we are talking about dotted lists and not ‘proper’ ones?

No. Dotted lists are just a notational convention. All lists can be written in dotted notation.

You can define NIL as follows:

    (setf NIL (cons 0 0)))
    (setf (car NIL) NIL)
    (setf (cdr NIL) NIL)
Then:

    (defun null (thing) (eq thing NIL))
You also have to add a bunch of special cases to other functions:

    (defun cl-style-consp (thing)
      (and (consp thing) (not (null thing)))
    (defun cl-style-symbolp (thing)
      (or (symbolp thing) (null thing))
    (defun cl-style-symbol-name (thing)
      (if (null thing) "NIL" (symbol-name thing)))
and a few others.

In fact, many CL implementations actually implement NIL that way so that CAR and CDR of NIL return NIL without having to make that a special case.

Re: The empty list

#12
post #10

Earlier quoted context omitted.

Yep. It's probably the case that one should have a more complicated serializer / deserializer for JSON in CL (one that takes into account the expected JSON datatypes) because JSON is yet another type and value system from Scheme's and CL's, but there's an isomorphism from the Scheme one to the JSON one and there's no such similar isomorphism for the primitive CL types (though were one so inclined, one could certainly…

You want empty lists because you can't iterate a null. So an empty list should be an empty list, otherwise it will require special code to check for the null case.

Do you mean you can't iterate a null in JavaScript or in LISP?

You can't iterate a null in JavaScript, but that's a design decision of the language that could have gone another way; `for (const elem of null) {do();}` could have been specified to be valid JavaScript that never calls `do()`, but it wasn't because it wasn't.

Re: The empty list

#13
post #6

It's very difficult to deserialize in serialize things like yaml and json in CL because it doesn't have a distinct false object. When you do deserialize `false` it turns into nil. Then when you serialize it back again it turns into `null`. From a practical perspective, this is annoying. I don't hate using it as a language, it's fine, but because it's different enough than other languages it confuses people.

I share your frustration, particularly since one could add a canonical false value to CL in a backwards-compatible way. But it's too late now. But as a practical solution you could de-serialize false into, say, :false, in order to distinguish them from empty lists, and then do a post-processing step to turn those into nils if you wanted to.

> you could de-serialize false into, say, :false ...

That's the approach that st-json [0] builds on:

- true and false become :true and :false, respectively

- [] becomes nil

- {} becomes #s(st-json:jso :alist nil)

---

[0] in QuickLisp and at https://github.com/marijnh/ST-JSON

Re: The empty list

#14
post #10

Earlier quoted context omitted.

You want empty lists because you can't iterate a null. So an empty list should be an empty list, otherwise it will require special code to check for the null case.

Do you mean you can't iterate a null in JavaScript or in LISP? You can't iterate a null in JavaScript, but that's a design decision of the language that could have gone another way; `for (const elem of null) {do();}` could have been specified to be valid JavaScript that never calls `do()`, but it wasn't because it wasn't.

Well if you could iterate a null, you'd also be able to sum 2 nulls. And you'd need null to carry a length (of zero, I presume).

Re: The empty list

#15
post #13
post #6

Earlier quoted context omitted.

I share your frustration, particularly since one could add a canonical false value to CL in a backwards-compatible way. But it's too late now. But as a practical solution you could de-serialize false into, say, :false, in order to distinguish them from empty lists, and then do a post-processing step to turn those into nils if you wanted to.

> you could de-serialize false into, say, :false ... That's the approach that st-json [0] builds on: - true and false become :true and :false, respectively - [] becomes nil - {} becomes #s(st-json:jso :alist nil) --- [0] in QuickLisp and at https://github.com/marijnh/ST-JSON

Yeah, good point. IMHO the lack of a canonical serialization for hash tables is a much more serious omission than not having a separate boolean false value.

Re: The empty list

#16
I like that the article was non judgement. The real world is messy and Common Lisp formalized existing practice among several branches of an already old language from before programming language theory.

There are a number things worth “fixing” and it’s delightful that so much interest and implementation in this regard has been sustained for so long.

But to the ideologues, I can only quote Emerson: "A foolish consistency is the hobgoblin of little minds, adored by little statesmen and [programming] philosophers and divines."

Re: The empty list

#17
I don't see the benefit of the Scheme approach at all. As far as I'm concerned, the empty list being also the false object makes certain list functions more elegant to implement and it is mostly irrelevant elsewhere.

Re: The empty list

#18
I've been trying to learn CL by using it to do AOC. As someone coming from mostly Python, there is a lot about it that confuses and, occasionally, frustrates me.

Maybe I'm just missing something obvious but it doesn't seem like you can start with an empty list that you can repeatedly append to. The empty list is nil, and `(append nil foo)` seems to just yield `foo`, not `(list foo)`. So trying to append to that object will (probably) raise an error.

Re: The empty list

#19
post #11
post #8

Earlier quoted context omitted.

I tend to agree but would be happy to be proven wrong by more knowledgeable folks in these comments. However I assume here we are talking about dotted lists and not ‘proper’ ones?

No. Dotted lists are just a notational convention. All lists can be written in dotted notation. You can define NIL as follows: (setf NIL (cons 0 0))) (setf (car NIL) NIL) (setf (cdr NIL) NIL) Then: (defun null (thing) (eq thing NIL)) You also have to add a bunch of special cases to other functions: (defun cl-style-consp (thing) (and (consp thing) (not (null thing))) (defun cl-style-symbolp (thing) (or (symbolp thing)…

In other words

    CL-USER> (equalp '(1 2 3)
                     '(1 . (2 . (3 . nil))))
    => T

Re: The empty list

#20

It's very difficult to deserialize in serialize things like yaml and json in CL because it doesn't have a distinct false object. When you do deserialize `false` it turns into nil. Then when you serialize it back again it turns into `null`. From a practical perspective, this is annoying. I don't hate using it as a language, it's fine, but because it's different enough than other languages it confuses people.

Yep. It's probably the case that one should have a more complicated serializer / deserializer for JSON in CL (one that takes into account the expected JSON datatypes) because JSON is yet another type and value system from Scheme's and CL's, but there's an isomorphism from the Scheme one to the JSON one and there's no such similar isomorphism for the primitive CL types (though were one so inclined, one could certainly…

> why does JavaScript need a false and an empty array and a null and even an undefined?)

Why does Lisp need a 0 and a nil? Because numbers are conceptually different from lists, and the number 0 is conceptually different from no number at all.

Why does JavaScript need a false and an empty array and a null and an undefined? Because all of those represent different concepts. Trying to stuff as many concepts as possible into a single representation doesn't necessarily make a language better (though I'm certainly not claiming that JavaScript is the epitome of good language design).

Post reply on HN