Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Clojure is an empty list a sequence of infinite nulls?

Tags:

clojure

I am learning the concept of sequence and nil in Clojure. This was the result of a small experimentation.

1:6 user=> (first '())
nil
1:7 user=> (rest '())
()
1:8 user=> (first (rest '()))
nil

Does this mean that '() is actually a sequence of nils?

like image 926
unj2 Avatar asked Jul 23 '09 20:07

unj2


4 Answers

If you want to test whether the "rest" of a collection is empty, use next.

user> (next '(foo bar))
(bar)
user> (next '())
nil
user> (doc next)
-------------------------
clojure.core/next
([coll])
  Returns a seq of the items after the first. Calls seq on its
  argument.  If there are no more items, returns nil.

"nil-punning" (treating an empty collection/seq and nil as the same thing) was removed last year in favor of fully-lazy sequences. See here for a discussion leading up to this change.

like image 89
Brian Carper Avatar answered Nov 11 '22 09:11

Brian Carper


first and rest are functions that apply to a logical structure (a seq) and not on the linked cons structure of a list (as in other lisps).

Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and unlike most Lisps where the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences.

http://clojure.org/sequences

The behavior is a result of the definition of the function and not determined by the primitive structure of the data.

like image 30
Pinochle Avatar answered Nov 11 '22 10:11

Pinochle


No - an empty list is not the same as an infinite sequence of nils

This is relatively easy to show. Suppose we have:

(def infinite-nils (repeat nil)) ; an infinite lazy sequence of nils
(def empty-list    '())          ; an empty list

They have different numbers of elements:

(count infinite-nils) => doesn't terminate
(count empty-list)    => 0

Taking from them:

(take 10 infinite-nils)  => (nil nil nil nil nil nil nil nil nil nil)
(take 10 empty-list)     => ()

If you call seq on them you get

(seq inifinite-nils) => sequence of infinite nils
(seq empty-list)     => nil

The confusion in the original can largely be resolved by understanding the following facts:

  • '() is a collection (a persistent list), not a sequence. However it is sequential, so you can call seq on it to convert it into sequence.
  • nil is the empty sequence - so therefore (seq '()) returns nil, as does (seq (rest '()))
  • first returns nil on an empty sequence - hence why (first (rest '())) is nil.
like image 2
mikera Avatar answered Nov 11 '22 08:11

mikera


Also learning Clojure.

For empty sequences, rest returns a sequence for which seq returns nil.

That's why you get that behavior.

I assume this is to simplify recursing on sequences until they are empty, and probably other smartypants reasons...

like image 1
Dan Fitch Avatar answered Nov 11 '22 10:11

Dan Fitch