common lisp cons creates a list from two symbols, clojure cons requires a seq to cons onto?
-
13-09-2020 - |
Question
(Disclaimer - I'm aware of the significance of Seqs in Clojure)
In common lisp the cons function can be used to combine two symbols into a list:
(def s 'x)
(def l 'y)
(cons s l)
In clojure - you can only cons onto a sequence - cons hasn't been extended to work with two symbols. So you have to write:
(def s 'x)
(def l 'y)
(cons s '(l))
Is there a higher level pattern in Clojure that explains this difference between Common LISP and Clojure?
Solution
In Clojure, unlike traditional Lisps, lists are not the primary data structures. The data structures can implement the ISeq interface - which is another view of the data structure it's given - allowing the same functions to access elements in each. (Lists already implement this. seq?
checks whether something implements ISeq.(seq? '(1 2)), (seq? [1 2]))
Clojure simply acts differently (with good reason), in that when cons
is used, a sequence (it's actually of type clojure.lang.Cons
) constructed of a
and (seq b)
is returned. (a
being arg 1 and b
arg 2) Obviously, symbols don't and can't implement ISeq.
Sequences screencast/talk by Rich Hickey However, note that rest
has changed, and it's previous behaviour is now in next
, and that lazy-cons
has been replaced by lazy-seq
and cons
.
OTHER TIPS
In Common Lisp CONS creates a so-called CONS cell, which is similar to a record with two slots: the 'car' and the 'cdr'.
You can put ANYTHING into those two slots of a cons cell.
Cons cells are used to build lists. But one can create all kinds of data structures with cons cells: trees, graphs, various types of specialized lists, ...
The implementations of Lisp are highly optimized to provide very efficient cons cells.
A Lisp list is just a common way of using cons cells (see Rainer's description). Clojure is best seen as not having cons cells (although something similar might hide under the hood). The Clojure cons
is a misnomer, it should actually just be named prepend
.
In Clojure the use of a two-element vector is preferred: [:a :b]
. Under the hood such small vectors are implemented as Java arrays and are extremely simple and fast.
A short hand for (cons :a '(:b))
(or (cons :a (cons :b nil))
) is list
: (list :a :b)
.
When you say
> (cons 'a 'b)
in common lisp you dont get a list but a dotted pair: (a . b)
, whereas the result of
> (cons 'a (cons 'b nil))
is the dotted pair (a . ( b . nil))
.
In the first list the cdr()
of that is not a list, since it is here b
and not nil
, making it an improper list. Proper lists must be terminated by nil
. Therefore higher order functions like mapcar()
and friends won't work, but we save a cons-cell. I guess the designers of Clojure removed this feature because of the confusion it could cause.