Hacker News new | past | comments | ask | show | jobs | submit login

The original discussion is here: https://groups.google.com/g/comp.lang.lisp/c/T_Tozq2P53I/m/N...

I found it intriguing that the original post there claims that

  (cons (list 1 2) (list 3 4))
intuitively seems to have the length 2 whereas the correct length is 3. I find 3 more intuitive though. It could be because right from my early days of learning various Lisps, I learnt about lists in terms of cons cells.

There are many ways to explain this, such as by drawing diagrams of the cons cells from first principles, printing out each cons and list on a REPL and confirming the equivalences, etc. Here's one that happens to be my take on it. I'll be (ab)using the equals sign (=) to mean that the expression on the LHS and the one on the RHS are equivalent.

First let us build a list of three items using cons cells:

  (cons 4 nil) = (list 4)

  (cons 3 (cons 4 nil)) = (list 3 4)                [1]

  (cons 'x (cons 3 (cons 4 nil))) = (list 'x 3 4)   [2]
Now let us build a list of two items using cons cells:

  (cons 1 nil) = (list 1)

  (cons 1 (cons 2 nil)) = (list 1 2)                [3]
Now substituting LHS and RHS of [3] into 'x in LHS and RHS of [2], respectively, we get

  (cons (cons 1 (cons 2 nil)) (cons 3 (cons 4 nil))) = (list (list 1 2) 3 4)
Simplifying the LHS above using [3] and [1], we get

  (cons (list 1 2) (list 3 4)) = (list (list 1 2) 3 4)
Clearly, the length of RHS is 3.

From the REPL:

  CL-USER> (cons (list 1 2) (list 3 4))
  ((1 2) 3 4)
  CL-USER> (list (list 1 2) 3 4)
  ((1 2) 3 4)
  CL-USER> (length (cons (list 1 2) (list 3 4)))
  3
  CL-USER> (length (list (list 1 2) 3 4))
  3
  CL-USER>
Also, on Emacs:

  ELISP> (cons (list 1 2) (list 3 4))
  ((1 2)
   3 4)

  ELISP> (list (list 1 2) 3 4)
  ((1 2)
   3 4)

  ELISP> (length (cons (list 1 2) (list 3 4)))
  3 (#o3, #x3, ?\C-c)
  ELISP> (length (list (list 1 2) 3 4))
  3 (#o3, #x3, ?\C-c)
  ELISP>
See also: https://gigamonkeys.com/book/they-called-it-lisp-for-a-reaso...



> intuitively seems to have the length 2 whereas the correct length is 3. I find 3 more intuitive though. It could be because right from my early days of learning various Lisps, I learnt about lists in terms of cons cells.

That's just how cons is defined. the first argument is a list and the second is an arbitrary object, and the result has the elements from the list plus the other object. It doesn't take a bunch of algebraic manipulation to understand this definition. It just takes a recognition that an "arbitrary object" could be a list, as well as a recognition that the other definition you imply ("make a new list with both arguments as elements") would have to either be variadic (which in turn would obviate `list`) or would only ever be able to make lists of exactly 2 elements. (The point is that `cons` can serve as a simpler primitive, and `list` can be implemented in terms of it.)


That original post started with

> (list 1 2 3) == (cons 1 (cons 2 (cons 3 nil)))

and I'd have answered that cons could be a variable-arity function such that

> (list 1 2 3) == (cons 1 2 3 nil)

and maybe that'd help this newbie's intuition. (Common Lisp does have this variable-arity cons but by a different name list*, for some reason.)


Note that the value returned by cons is guaranteed to have type cons, and it is guaranteed that a fresh cons is created. Neither is true for list*; note that its return type is t.


To me, the form is not intuitive, but the result is:

  ((1 2) 3 4)
Someone else in that thread mentioned that CONS is basically adding (1 2) to the front of the (3 4) list, and that helped me understand it better.


Something you know because of what you learned cannot be called "intuitive".

Intuitive means that, having studied nothing, you somehow make the right guesses about something.

A device is intuitive if you can chuck the user manual aside as you unbox it, and proceed to use it without difficulty or puzzlement.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: