zepto
zepto copied to clipboard
RFC: make empty list the identity of `cons`
cons
is the zepto function to append something to the start of a list. It is quite useful for working with lists, even though the behavior of zepto's implementation of this function differs from the standard Scheme implementation.
A few motivating examples of how cons
currently works:
(cons 1 [2]) ; [1 2]
(cons [3] [4]) ; [[3] 4]
(cons 1 (cons 2)) ; pair[1, 2]
(cons 1) ; pair[1]
Ass you see, its normal type is a dotted list, but it will also work with regular lists. Well, that's nice already, isn't it? But what if we call it without an argument?
(cons) ; explosion!
It will fail! But wait, we just said it has a type associated with it! Wouldn't it make sense to return an empty dotted list then? Well... yes. The only problem with that is that dotted lists cannot be empty. They require at least one element to exist.
Hum... But, what if we do the next best thing then and just return an empty list? That violates the whole "its type is a dotted list" invariant, but it is really muddy to begin with and dotted lists should only be worked with if you really have to (i.e. in really fancy macros).
So, what this RFC proposes is the following behavior:
(cons) ; []
I hope that makes sense! Cheers
An experimental implementation of this feature is provided in the new-cons
branch.
With this change, what would be the result of (cons 1 (cons))
for example?
[1]
, because it would add 1
to an empty list.
What is []
again?
The empty list, similar to Javascript, Python, or Ruby.
Ok, but does that mean there are multiple ways of writting a list and an empty list?
(1 2 3 )
()
(nil)
[1 2 3 ]
[]
[nil]
(list 1 2 3)
(list)
(list nil)
I guess my question could be why returning []
and not ()
?
So we now for sure this is an empty list and not parenthesis meant for something else?
Okay, let me rephrase: []
is a quoted list[1]. Quoting is, as per usual in Lisp, the facility to separate code and data. To illustrate your example:
(1 2 3) ; will try to evaluate 1 as a function with the arguments 2 and 3
() ; cannot be evaluated
(nil) ; evaluates to nil, because nil is both a function and a value
[1 2 3] ; is a list of 1, 2, and 3
[] ; is an empty list
[nil] ; is a list of one element, nil
(list 1 2 3) ; list is a function to construct a list, so this list will be constructed at runtime
(list) ; will return []
(list nil) ; will return [nil]
; this form is a little like new Array(1,2,3) in Javascript vs. [1, 2, 3] in Javascript. One is a constant,
; the other is allocated at runtime.
I hope this helps.
So what we are really returning is a list datastructure, not code, thus []
, which is equivalent to a quoted list '()
or (quote ())
. Reader macros FTW.
[1] Actually it is a reader macro for (quote ())
.