Live data from Hacker News

The empty list

tfeb.org

41–50 of 109 posts

Re: The empty list

#41

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 objec…

APPEND is for concatenating two lists. If you're trying to add a value, then if your NIL is already in a variable, use PUSH to add the value (to the front). This will build the result list in reverse, so you can NREVERSE it at the end.

There’s a relatively straightforward deque implementation too if you need to append in addition to pushing. It can require a little rebalancing, but I imagine it amortizes to constant time.

Re: The empty list

#42
post #32
post #30

Earlier quoted context omitted.

That's one reason. Another is that it allows you to use the idiom (if X ...) to test for non-null rather than (if (not (null X)) ...)

Indeed, although some languages achieve the same by defining multiple falsy values, e.g. JS has 9 such values: https://developer.mozilla.org/en-US/docs/Glossary/Falsy

Yeah, but this causes its own set of problems when, for example, you are surprised that 0.0 is false but -0.0 is true.

In general, punning of any kind is a Really Bad Idea when code gets complicated.

Re: The empty list

#43

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.

> It's very difficult to deserialize in serialize things like yaml and json in CL because it doesn't have a distinct false object.

Its not particularly hard to represent JSON’s type system in CL and deserialize JSON to CL objects.

Its also not particularly hard to construct and use a model of CL data in JSON from CL. (Its even easier with YAML.)

OTOH, yes, JSONs data model is almost exactly JS’s data model (minus anything callable, which js a lot of JS, and with a slightly different model of numbers, but anything that doesn’t exactly match JS’s model is canonically unreliable and so discouraged), So with any thing other than JS using JSON, you have to determine if your use case is modeling your language’s data in JSON or JSON’s data model in your language, while with a particular subset of JS you can just ignore the distinction.

Re: The empty list

#44
post #38

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.

Serialization formats not designed specifically for the language should not be treated as serializers for objects in that language. That is, JSON is not a representation of objects in your language. It's your application that holds a representation of JSON data. If you're not paying attention to the translation layer between your native objects and the JSON ones, you'll hit problems sooner or later.

JSON is the JavaScript Object Notation; it's in the name! The closer your language's object model is to JavaScript, the more likely it is you'll get away with treating it as a direct serialization format. Conversely, the further your language is from JavaScript, the more you'll need to add types specifically to represent JSON.

Re: The empty list

#45
post #29

Earlier quoted context omitted.

Correct. Which could, of course, all be defined. - null + null === null ; list + null === list; null + list === list - null.length === 0 /* should probably make it a runtime error to write this property, or allow it but have the result be a list with length elements, all undefined */ (Note: somewhat hilariously, null + null is already defined in JavaScript. It, of course, is 0. Wat. ;) ) Whether null and empty list s…

Why not just have empty lists instead of null then? :D Seems simpler.

I agree. I use quite a few languages that don't have the "scorpion in a jar" problem where an argument might be an empty list or null (some that address it with static typing, some where the two values are the same value).

Re: The empty list

#46

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 objec…

I think what you want to do is

  (cons 'foo nil)
It's in the oposite order. It starts with the empty list and it adds foo in the head.

An extension is

  (cons 'bar (cons 'foo nil))
that is equivalent to

  (list 'bar 'foo)

Re: The empty list

#47
post #27

Earlier quoted context omitted.

> in a backwards-compatible way. But it's too late now. You just contradicted yourself.

No, that's not a contradiction. To add a canonical false value you would have to change the semantics of the language, which means you have to change the standard. In general changing standards is possible, but in the case of CL it is not possible for practical reasons: changing standards costs money and no one would fund such an effort. CL is moribund, not unlike Smalltalk, APL, and COBOL.

>CL is moribund, not unlike Smalltalk, APL, and COBOL.

If someone wants to do some hobby/small-scale but complex programming in LISP, what kind of dialect should they use? Scheme/Racket or something else?

Re: The empty list

#48
post #27

Earlier quoted context omitted.

No, that's not a contradiction. To add a canonical false value you would have to change the semantics of the language, which means you have to change the standard. In general changing standards is possible, but in the case of CL it is not possible for practical reasons: changing standards costs money and no one would fund such an effort. CL is moribund, not unlike Smalltalk, APL, and COBOL.

>CL is moribund, not unlike Smalltalk, APL, and COBOL. If someone wants to do some hobby/small-scale but complex programming in LISP, what kind of dialect should they use? Scheme/Racket or something else?

Personally I do all my personal coding in CL but it's a matter of taste. Another word for "moribund" is "stable" and that can be a good thing. But it really is mostly personal preference. And you might want to add Clojure to your list of languages to consider.

The reason I like CL is that I find it is a local optimum impedance match for my brain in language design space. But that is at least in part because I have been using it for 35 years so I am used to its quirks (of which there are many). But it also has lots of really nice features, some of which are still unique to CL and which I find indispensable to my coding style. Generic functions are at the top of that list, and a close second is the macro system.

Re: The empty list

#49
post #29

Earlier quoted context omitted.

Why not just have empty lists instead of null then? :D Seems simpler.

I agree. I use quite a few languages that don't have the "scorpion in a jar" problem where an argument might be an empty list or null (some that address it with static typing, some where the two values are the same value).

I'm not familiar with the "scorpion in a jar" idiom; guessing it's something like [to kill the scorpion you have to open the jar]... care to elucidate?

Re: The empty list

#50

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 objec…

The easiest way to think about this, as Tim mentions in his article, is that in Common Lisp, you can write nil as '(), so if foo is defined as the list (d e f), (append nil foo) is equivalent to (append '() '(d e f)) which more obviously evaluates to (d e f), just as (append '(a b c) '(d e f)) evaluates to (a b c d e f). It's better to think of Lisp append's first argument being appended onto its second: (append '(a b) '(c d)) => (cons 'a (append '(b) '(c d))) => (cons 'a (cons 'b (append '() '(c d)))) => (cons 'a (cons 'b '(c d))) => (cons 'a '(b c d)), which evaluates to (a b c d). The lists '(a b) and '(c d) are still unaltered at the end of the computation, and a new list '(a b c d) is returned by the call to append.
Post reply on HN