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?

Was it helpful?

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.

Clojure.org/sequences

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.

clojure.lang.RT

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top