Most active commenters
  • lisper(6)
  • pmarreck(5)

←back to thread

Hofstadter on Lisp (1983)

(gist.github.com)
372 points Eric_WVGG | 17 comments | | HN request time: 0.988s | source | bottom
Show context
susam ◴[] No.41861244[source]
> Attempting to take the car or cdr of nil causes (or should cause) the Lisp genie to cough out an error message, just as attempting to divide by zero should evoke an error message.

Interestingly, this is no longer the case. Modern Lisps now evaluate (car nil) and (cdr nil) to nil. In the original Lisp defined by John McCarthy, indeed CAR and CDR were undefined for NIL. Quoting from <https://dl.acm.org/doi/pdf/10.1145/367177.367199>:

> Here NIL is an atomic symbol used to terminate lists.

> car [x] is defined if and only if x is not atomic.

> cdr [x] is also defined when x is not atomic.

However, both Common Lisp and Emacs Lisp define (car nil) and (cdr nil) to be nil. Quoting from <https://www.lispworks.com/documentation/HyperSpec/Body/f_car...>:

> If x is a cons, car returns the car of that cons. If x is nil, car returns nil.

> If x is a cons, cdr returns the cdr of that cons. If x is nil, cdr returns nil.

Also, quoting from <https://www.gnu.org/software/emacs/manual/html_node/elisp/Li...>:

> Function: car cons-cell ... As a special case, if cons-cell is nil, this function returns nil. Therefore, any list is a valid argument. An error is signaled if the argument is not a cons cell or nil.

> Function: cdr cons-cell ... As a special case, if cons-cell is nil, this function returns nil; therefore, any list is a valid argument. An error is signaled if the argument is not a cons cell or nil.

replies(6): >>41861327 #>>41861751 #>>41862379 #>>41862873 #>>41862933 #>>41868929 #
1. lisper ◴[] No.41862873[source]
> Modern Lisps now evaluate (car nil) and (cdr nil) to nil.

Scheme doesn't. Taking the CAR or CDR of nil is an error.

replies(3): >>41863007 #>>41863233 #>>41868861 #
2. anthk ◴[] No.41863007[source]
Elisp and CL do.
3. susam ◴[] No.41863233[source]
Does Scheme even have NIL in the sense that other Lisps like CL or Elisp have? I mean in Common Lisp, we have:

  CL-USER> (symbolp nil)
  T
  CL-USER> (atom nil)
  T
  CL-USER> (listp nil)
  T
Similar results in Emacs Lisp. But in MIT Scheme, we get:

  1 ]=> nil

  ;Unbound variable: nil
Of course, we can use () or (define nil ()) to illustrate your point. For example:

  1 ]=> (car ())

  ;The object (), passed as the first argument to car, is not the correct type.
But when I said NIL earlier, I really meant the symbol NIL that evaluates to NIL and is both a LIST and ATOM. But otherwise, yes, I understand your point and agree with it.
replies(2): >>41863266 #>>41865146 #
4. dokyun ◴[] No.41863266[source]
I don't believe so, standardly. Guile scheme added the value `#nil' which is equivalent to NIL and distinct from #f and the empty list, but this was done in order to support Emacs Lisp.
5. lisper ◴[] No.41865146[source]
> Does Scheme even have NIL in the sense that other Lisps like CL or Elisp have?

No. It has an empty list, which is a singleton atomic value whose type is not shared with any other object, and it has a boolean false value, which is distinct from the empty list. A user can create a symbol named NIL, but that symbol has no characteristics that distinguish it from any other symbol. You can, of course, bind NIL to either the empty list or boolean false (or any other value) but it can only have one value at a time (per thread).

replies(1): >>41868328 #
6. blenderob ◴[] No.41868328{3}[source]
> No. It has an empty list

If there is no nil in scheme, what did you mean when you said that taking car or dr of nil is an error in scheme?

replies(1): >>41870464 #
7. pmarreck ◴[] No.41868861[source]
I'm not a LISPer but this just seems more correct to me, since stricter is usually more correct.

Ruby (not a lisp but bear with me) started to do this more correctly IMHO where a nil would start throwing errors if you tried to do things with it BUT it would still be equivalent to false in boolean checks.

replies(1): >>41870516 #
8. lisper ◴[] No.41870464{4}[source]
You need to read more carefully. The claim was not that there is no NIL in Scheme, the claim was that Scheme does not have a "NIL in the sense that other Lisps like CL or Elisp have". There is a NIL is Scheme, but it's just a symbol like any other with no privileged status. Also, in colloquial use, the word "nil" is often taken to be a synonym for "the empty list" even when talking about Scheme.
9. lisper ◴[] No.41870516[source]
It depends on what you are trying to optimize for. There is a benefit to punning the empty list and boolean false. It lets you shorten (not (null x)) to just x, and that is a common enough idiom that it actually makes a difference in real code. And there is a benefit to being able to say or type "nil" instead of "the empty list" because "nil" is shorter. But yeah, for modern production code, I agree that stricter is better, all else being equal.
replies(2): >>41880552 #>>41880728 #
10. pmarreck ◴[] No.41880552{3}[source]
I love that I started out saying "I'm not a LISPer" and someone whose username is literally "lisper" responded. >..<

Is there a purely functional Lisp that compiles to machine code yet?

replies(1): >>41880724 #
11. lisper ◴[] No.41880724{4}[source]
That depends on what you mean by "purely functional Lisp". You can write purely functional code in any Lisp, and you can compile any Lisp to machine language, and this has been true for decades. AFAIK there is no Lisp that enforces purely functional programming, but it's easy to build one if that's what you want.
replies(1): >>41895770 #
12. pmarreck ◴[] No.41880728{3}[source]
sorry for another lisp question

if from a syntactic-flavor perspective, endless parentheses turn me off, but also cleanly map to significant indentation (where any new open paren is a new indentation level and a close paren maps to a backdent), has anyone tried a Lisp that uses indentation instead of parens?

I'm probably failing to consider edge cases but it seems like a potentially simple tweak that might make lisps more palatable to many

imagine that, a lisp without parens... (empty cons literals... crap, that's 1 edge case!)

replies(3): >>41881057 #>>41882476 #>>41882596 #
13. lisper ◴[] No.41881057{4}[source]
What do you think is more likely, that you are the first person to ever think of this, or that others have tried to do this and failed for some reason? The more interesting question is: what is that reason? I'm not going to tell you the answer, you will learn more if you figure it out yourself, but here's a hint: look at Python's syntax, and ask yourself if it is possible to write an editor that auto-indents Python. (Second hint: look at what happens when you edit Python code in Emacs. Third hint: look at what happens when you put in PASS statements.)
replies(1): >>41892640 #
14. kazinator ◴[] No.41882476{4}[source]
Alternative syntaxes for Lisp dialects, some of them indentation-sensitive, have been proposed numerous times over the entire history of the Lisp family.

From the start, John MacCarthy believed that Lisp would be programmed using M-expressions and not S-expressions. M-expressions are still quite parenthetical, but have some syntactic sugar for case statements and such.

In the second incarnation of the Lisp project, which was called Lisp 2, MacCarthy's team introduced an Algol-like syntactic layer transpiling to Lisp. This was still in the middle 1960's! The project didn't go anywhere; Lisp 1.5 outlived it, and is the ancestor of most other Lisp stuff.

In the early 1970's, Vaughan Pratt (of "Pratt parser" fame) came up with CGOL: a another alternative programming language syntax layer of Lisp.

Scheme has a "sweet expressions" SRFI 110 which I think was originated by David Wheeler. It is indentation-based syntax.

The Racket language has numerous language front ends, which are indicated/requested in the source file with #lang. I think one of them is sweet expressions or something like it.

Those are just some of the notable things, not counting lesser known individual projects.

15. lispm ◴[] No.41882596{4}[source]
> I'm probably failing to consider edge cases but it seems like a potentially simple tweak that might make lisps more palatable to many

Lisp came out in 1960. The s-expression-only syntax was an accident or a discovery - depending on one's view. Over the many years no attempt to add significant indentation syntax without parentheses gained more than a few users. Syntax variants without parentheses (and no significant indentation) only had a marginally better fate. Sometimes it even contributed to the failure of Lisp derived languages (-> Lisp 2, Dylan)...

16. pmarreck ◴[] No.41892640{5}[source]
I never suggested that I was the first person to think of this; not having dealt with any Lisp since (hmmm) 1990 via Scheme in my introductory CS 212 class at Cornell probably has something to do with my ignorance of the prior art in this area. I do like your approach of breadcrumbing me instead of giving me the answer, though... best I can guess is "tooling" and simply that S-expressions are simply too embedded in the minds of the Lisp community at this (or previous) point(s).

I also don't deal with significant-indentation in languages usually (and have a strong Python distaste); though I've been playing with Roc (https://www.roc-lang.org/), which has this, and have used HAML (https://haml.info/) in the past, where it seemed useful. I suppose auto-indenting is impossible in a significant-indentation language depending on what the editor can intuit based on how the previous line ended, but I don't think I'd need that feature as long as it simply held the current indentation and just let me hit Tab or Backspace. (I could see things becoming a mess if you manage to screw up the indentation, though.)

I did research "sweet expressions" (which are apparently also called T-expressions) and found the prior art there in Scheme and Lisp, and a library called "sweet" for Racket (which is another intriguing lisp dialect!). These might have gotchas, but apparently they've sufficiently solved the problem enough to be usable.

I do simply like how "T-expressions" look. Which is something I guess I care about, although I know that's not a universal among coders. (My guess is that those who care about such things are simply not 100% left-brained about their coding and are invested in the "writing" aspect of the craft.)

17. pmarreck ◴[] No.41895770{5}[source]
That is what I want.

Turns out that LFE (Lisp-Flavored Erlang) exists…

Wait, doesn’t Clojure have this, to a large degree at least?