masak / bel

An interpreter for Bel, Paul Graham's Lisp language
GNU General Public License v3.0
25 stars 1 forks source link

Test that 'cons' builds a new list, as it promises, and doesn't just return 'args' #422

Closed masak closed 1 year ago

masak commented 2 years ago
(def cons args
  (reduce join args))

Add a test that makes sure the implementation doesn't just do this:

(def cons args
  args)

bellanguage.txt makes this point for list:

Or more precisely, returns a newly made list of its arguments. If you're wondering why we bother appending args to nil rather than simply returning it, the reason is that appending a list to nil will also copy it.

If we defined list as

(def list args args)

and it was called thus

(apply list x)

then the value that list returned would be the same list as x-- not merely a list with the same elements, but the same pair-- meaning if we modified the value we got from list, we'd also be modifying the object up in the calling code.

But the same, it feels like, is true of cons.

masak commented 1 year ago

Hm, but there's something more going on here that makes it not exactly the same as list. Look:

> (set L1 '(1 2 3))
(1 2 3)
> (apply cons L1)
(1 2 . 3)
> (apply cons L1 nil)
(1 2 3)
masak commented 1 year ago

Hm, but there's something more going on here that makes it not exactly the same as list.

Right, cons is actually Kernel's list*, whose equations (quoted from the specification) are these:

                  (list arg1)arg1 (list arg1 arg2 . args)(cons arg1 (list* arg2 . args))

In other words, the implementation of cons can't actually cheat in a simple way as the OP imagines; list can, but list*/cons can't. So there's nothing much to test, methinks. Closing.