this may be a silly argument, but:

 (list? '()) returns true

(list? nil) returns false
(list? 'nil) returns false.  I don't even know what it means.

therefore nil isn't a list.

Then again, I already chimed in.  a list isn't a set.  You said so in the
introduction.  Maybe set's need there own print representation, like <>
..... uh oh, starting to look like C++

That or find the unicode character for the zero with the line through it.


On Sat, Jan 24, 2009 at 3:43 AM, Mark Engelberg <mark.engelb...@gmail.com>wrote:

>
> Now that everyone's had a day to mull this puzzle over, here are my
> thoughts.
>
> One way to think about this, is to think about what the statement of
> purpose / contract of a generalized powerset function would be.  In
> general, most functions on seq-able objects return sequences.  For
> example, (rest [1 2 3]) yields (2 3). So we'd want to make powerset
> consistent with Clojure's general behavior.  Also, like most Clojure
> core functions, we'd expect sequences in the output to be lazy.  I
> think there are two basic lines of reasoning:
>
> 1.  The most straightforward generalization is:
> The powerset of a seq-able S is the (lazy) sequence of all (lazy)
> subsequences of (seq S).
> Thinking in this vein, you might figure that
> (powerset [1 2 3]) should be (nil (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3)).
> One way to rationalize it is that we really need to have an empty
> sequence in the sequence of answers, but there is no such thing as an
> empty sequence, so we must use nil.
> But the obvious flaw here is that this output violates our contract.
> We said we'd generate a sequence of sequences, but (seq? nil) is
> false.  nil is not the empty sequence, nor is it a sequence at all, so
> we haven't accurately captured the function's intention with this
> output.
>
> 2.  So one way to try to "fix" this problem is to put a concrete empty
> object in the output sequence.  Since sequences are inspired by lists,
> perhaps it makes sense to replace the nil with the empty list ().  So,
> (powerset [1 2 3]) yields (() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3)).
> But this has problems as well.  First, even though the result prints
> as a list of lists, it is important to remember that these things are
> not lists, but sequences derived from vectors (since the input is a
> vector in our example).  For example, (cons 1 [2 3]) prints as (1 2
> 3), but (list? (cons 1 [2 3])) is false.
> So it's difficult to even imagine what the contract would be for such
> a function.  Perhaps, "The powerset of a seq-able S is the (lazy)
> sequence of the empty list and all the (lazy) subsequences of (seq
> S)." would be one way to word the statement of purpose.  But if the
> input is a vector, it seems really odd to see an empty list in the
> output.  Why a list?
>
> So I think that the answer is that there is no good answer.  We really
> need an empty sequence here, and Clojure doesn't have such a notion.
>
> Clojure's choice to not have an empty sequence doesn't really cause
> any inconvenience when dealing with flat sequences, but I have found
> that it results in these sorts of dilemmas almost any time you deal
> with sequences of sequences.  In discussions about generating a
> sequence of all permutations, all combinations, etc., you inevitably
> end up with arguments over issues like what (permutations nil) should
> be (some say (nil), some say (()), and some say nil).  If you have an
> empty sequence, these issues go away.
>
> So ultimately, you just have to make a choice between nil and () and
> go with it.  It all comes down to a gut feeling about which one is a
> better stand-in for the notion of an empty sequence, even though
> neither one truly is the empty sequence.  In practice, it doesn't seem
> to matter too much which choice you make.  nil and () are almost
> entirely interchangeable.
> (cons 1 nil) is the actual concrete list (1), just as (cons 1 '()) is.
> (conj nil 1) is the same as (conj '() 1)
> (first nil) and (first '()) both yield nil.
> (rest nil) and (rest '()) both yield nil.
> (empty? nil) and (empty? '()) both yield true
> (seq nil) and (seq '()) both yield nil.
>
> There are certainly a few differences, of course.  nil and '() respond
> differently to nil?, list? and not, for example.  But I haven't found
> these sorts of tests to be common in code operating on nested
> sequences.
>
> Even though it doesn't make a huge difference, the lack of a clearcut
> correct choice means that people will make different choices in
> different codebases, which could prove problematic.
>
> I have seen Rich's talk in which he explains that he chose to not have
> an empty sequence because which empty sequence should it be?  Empty
> list?  Empty vector?  Why should one empty object be privileged?  But
> this reasoning never resonated with me.  Sequences and lists have a
> special connection.  Sequences are intended to be a list-like
> interface.  So any sequence-producing function produces either a
> concrete list, or something that looks, feels, and tastes like a list.
>  I've already gotten used to seeing (rest [1 2 3]) producing (2 3) in
> the REPL (even though technically it's producing something list-like
> and not actually producing a list).  So to me, it would be perfectly
> natural to see (rest [1]) producing ().  () could reasonably serve as
> both the empty list and the empty sequence since lists and sequences
> are so closely related.
>
> I assume that a design decision as fundamental as the choice to have
> no empty sequence is probably set in stone at this point, so I think
> it's safe to assume that this dilemma is here to stay.  At the moment,
> I intend to advocate the use of nil over () as the closest surrogate
> for an empty sequence.  Clojure is designed to not give one empty
> collection privileged status, so putting () inside a sequence of
> sequences feels more wrong to me.  Furthermore, including nil is often
> more practical to code.  None of Clojure's built-ins actually return
> (), so it's only feasible to have () represent the empty sequence if
> it's the result of a separately-coded base case.  For many algorithms
> where the sequence is produced by mapping a function over a bunch of
> values, or by 'rest'ing a sequence until reaching empty, the algorithm
> will most naturally include nil in the sequence.  So for consistency,
> it's probably better to always choose nil over () in sequences of
> sequences.
>
> Anyone want to try to convince me otherwise?  If you think my logic is
> flawed, I'd love to hear your take on this problem.
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to