Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

empty list?

9 views
Skip to first unread message

mle...@bellatlantic.net

unread,
Feb 7, 1999, 3:00:00 AM2/7/99
to
How does one test to see if a list is empty? You see, I'm trying to get a
stopping condition to my recursive function:


(defun every-other-number (mylist)
(cond
((eq () mylist)) ;here's the line I though would stop the recursion
((not (numberp (car mylist))) (list (every-other-number(cdr mylist))))
((numberp (car mylist)) (car mylist) (every-other-number (cdr mylist)))))

;here's the line I'm using to test the function
(every-other-number '(my 94 geo metro is 5 years old))

Thanks in advance for your help.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Barry Margolin

unread,
Feb 7, 1999, 3:00:00 AM2/7/99
to
In article <79knsg$b0o$1...@nnrp1.dejanews.com>,

<mle...@bellatlantic.net> wrote:
>How does one test to see if a list is empty? You see, I'm trying to get a
>stopping condition to my recursive function:

The NULL function returns truth if given an empty list.

>(defun every-other-number (mylist)
> (cond
> ((eq () mylist)) ;here's the line I though would stop the recursion

That should work as well. There are a number of ways to check for empty
lists:

(null x) == (not x) == (eq '() x) == (typep x 'null).

> ((not (numberp (car mylist))) (list (every-other-number(cdr mylist))))

Why are you calling LIST here? I would expect the recursive call to return
a list, so you don't need to wrap it up in another list.

> ((numberp (car mylist)) (car mylist) (every-other-number (cdr mylist)))))

You're calling (car mylist) but not doing anything with the result. If you
want to include it in the result, you need something like

(cons (car mylist) (every-other-number (cdr mylist)))

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.

Rainer Joswig

unread,
Feb 7, 1999, 3:00:00 AM2/7/99
to
In article <79knsg$b0o$1...@nnrp1.dejanews.com>, mle...@bellatlantic.net wrote:

> How does one test to see if a list is empty? You see, I'm trying to get a
> stopping condition to my recursive function:
>
>

> (defun every-other-number (mylist)
> (cond
> ((eq () mylist)) ;here's the line I though would stop the recursion

> ((not (numberp (car mylist))) (list (every-other-number(cdr mylist))))

> ((numberp (car mylist)) (car mylist) (every-other-number (cdr mylist)))))
>

> ;here's the line I'm using to test the function
> (every-other-number '(my 94 geo metro is 5 years old))
>
> Thanks in advance for your help.
>
> -----------== Posted via Deja News, The Discussion Network ==----------
> http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

NULL thing
[Function]
returns true if thing is the empty list (), otherwise returns nil. This is
equivalent to the function not, except that null is normally used to check
for the empty list and not to invert. The programmer can express intent
by choice of function name.

See also:

http://www.harlequin.com/education/books/HyperSpec/Body/fun_null.html

--
http://www.lavielle.com/~joswig

Kent M Pitman

unread,
Feb 7, 1999, 3:00:00 AM2/7/99
to
mle...@bellatlantic.net writes:

> How does one test to see if a list is empty?

Restricting myself just to your question about emptiness, a few
notes before going after your more general question:

* (eq () mylist) as you have done in your example should terminate.
As to whether that' enough to make your program work, that's another
thing. But it didn't look to me like it was going to run out of control.

* (null mylist) is probably the function you were looking for.
It returns true if mylist is empty and false otherwise.

* A style note:

It's conventional to quote (). It's defined to self-evaluate,
but since lists have a meaning as programs and () is in the
messy middle ground where it has the look of a program that hasn't
been filled in, putting a quote in front of it helps make it clear
you intended it as data. So (eq '() mylist) does the same thing
but looks less grating to some of us.

* Another style note (more subtle and obscure, so ignore it if it
makes no sense to you or seems like it's more trouble than it's worth):

Although the comparison predicate EQ is symmetric behaves the same
regardless of argument order, I usually prefer to have the "variable"
argument first in the case where there is one variable and one constant.
There is a subtle English distinction reflected here; I'm not sure how
or whether it shows up in other languages, but to me if I say
"is this your coat?" i'm showing you an item and asking a question about
whether it is your coat (as opposed to someone else's). If I say
"is your coat this [one]?" i'm asking saying the "no" answer implies
I should seek another coat rather than another owner for this coat.
I choose to carry this distinction into code, so I write
(eq mylist '())
if I'm asking whether mylist has become the empty list yet,
and to me when I see
(eq '() mylist)
what I see is "has the empty list become mylist yet" which is virtually
nonsensical even though entirely meaningful programmatically.
Similarly, I prefer (= x 3) to (= 3 x).

Again, if this style distinction doesn't resonate with you,
ignore it for now. I offer it just in case you care...

Back to your program:

> (defun every-other-number (mylist)
> (cond
> ((eq () mylist)) ;here's the line I though would stop the recursion
> ((not (numberp (car mylist))) (list (every-other-number(cdr mylist))))
> ((numberp (car mylist)) (car mylist) (every-other-number (cdr mylist)))))

I didn't try it but this program looks to me like it will terminate.
Each call takes cdr of the list, so the list gets shorter. The test
for () in the first clause looks like it will stop when it's done. I
recommend explicitly returning '() in that case by the way, rather
than relying on the COND form to return NIL for you because you've
specified nothing ((eq () mylist) HERE).

In the second clause, you're wrapping a list around everything that's not
a list. I assume (since I didn't try it) that if you give it
(ALPHA BETA GAMMA DELTA) you'll get back ((((NIL)))). One pair of parens,
i.e., one list level, for each non-number. That's kind of an odd thing
to want for a return value. I'm not sure why you need the call to
LIST there at all.

In the third clause, you don't do anything to accumulate (car list).
The part after the test in a COND clause is an "implicit progn". That
is, (COND (test1 val1a val1b ...) (test2 val2a val2b ...) ...)
is equivalent to (COND (test1 (PROGN val1a val1b ...))
(test2 (PROGN val2a val2b ...)))
And since PROGN executes forms returning only the last of them,
the (car mylist) will be computed and then discarded, which may
not be what you want. The value you're returning in the third clause
is the result of the every-other-number. You might want to try again on
that.

My last hint to you is that you probably should look up the difference
between LIST and CONS. You may find CONS more useful than LIST once you
get various other problems with your program worked out.

Good luck.
--Kent

Erik Naggum

unread,
Feb 8, 1999, 3:00:00 AM2/8/99
to
* mle...@bellatlantic.net

| How does one test to see if a list is empty? You see, I'm trying to get a
| stopping condition to my recursive function:

the function ENDP returns true if the argument is the end of a proper
list (nil), false at any non-empty list (a cons), and signals an error in
every other situation.

#:Erik
--
Y2K conversion simplified: Januark, Februark, March, April, Mak, June,
Julk, August, September, October, November, December.

Barry Margolin

unread,
Feb 8, 1999, 3:00:00 AM2/8/99
to
In article <31274488...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:
>* Erik Naggum

>| the function ENDP returns true if the argument is the end of a proper
>| list (nil), false at any non-empty list (a cons), and signals an error in
>| every other situation.
>
>* Paul Dietz <di...@interaccess.com>
>| Rather, it *should* signal an error; it's not guaranteed to signal an
>| error in non-safe code.
>
> this one is a bit tricky. I have convinced myself that the "should" in
> ENDP is not quite the same "should" as elsewhere given the notes that
> license it to delay signaling an error until a dotted list has been
> processed all the way to the non-nil final element. can I convince
> anybody else of this interpretation?

Not me.

> Kent, an authoritative word on the intent?
>
> in any case, if it does not signal an error, it should definitely return
> true for any non-cons object.

The consequences are undefined if it's given a non-list, i.e. a non-null
atom. In unsafe code, ENDP is equivalent to:

(defun endp (arg)
(declare (type list arg))
(null arg))

The wording in the ANSI spec is essentially a rewording of what's in CltL:
"It is false of conses, true of NIL, and an error for all other arguments."
There's an implementation note encouraging them to signal an error for
non-lists, and it says that ENDP is for code where speed is more important
than safety; this resulted in the "should signal" wording in the standard.

Many implementations use a representation for NIL that's very easy to check
for, so (null arg) may be faster than (atom arg). You use ENDP so that
you'll get type checking if you want it (by setting safety high), but it
can be omitted if you want speed.

Paul Dietz

unread,
Feb 8, 1999, 3:00:00 AM2/8/99
to
Erik Naggum wrote:

> the function ENDP returns true if the argument is the end of a proper
> list (nil), false at any non-empty list (a cons), and signals an error in
> every other situation.

Rather, it *should* signal an error; it's not guaranteed


to signal an error in non-safe code.

Paul

Erik Naggum

unread,
Feb 8, 1999, 3:00:00 AM2/8/99
to
* Erik Naggum

| the function ENDP returns true if the argument is the end of a proper
| list (nil), false at any non-empty list (a cons), and signals an error in
| every other situation.

* Paul Dietz <di...@interaccess.com>


| Rather, it *should* signal an error; it's not guaranteed to signal an
| error in non-safe code.

this one is a bit tricky. I have convinced myself that the "should" in


ENDP is not quite the same "should" as elsewhere given the notes that
license it to delay signaling an error until a dotted list has been
processed all the way to the non-nil final element. can I convince
anybody else of this interpretation?

Kent, an authoritative word on the intent?

in any case, if it does not signal an error, it should definitely return
true for any non-cons object.

#:Erik

Kent M Pitman

unread,
Feb 9, 1999, 3:00:00 AM2/9/99
to
Erik Naggum <er...@naggum.no> writes:

> * Erik Naggum
> | the function ENDP returns true if the argument is the end of a proper
> | list (nil), false at any non-empty list (a cons), and signals an error in
> | every other situation.
>
> * Paul Dietz <di...@interaccess.com>
> | Rather, it *should* signal an error; it's not guaranteed to signal an
> | error in non-safe code.
>
> this one is a bit tricky. I have convinced myself that the "should" in
> ENDP is not quite the same "should" as elsewhere given the notes that
> license it to delay signaling an error until a dotted list has been
> processed all the way to the non-nil final element. can I convince
> anybody else of this interpretation?
>
> Kent, an authoritative word on the intent?

I believe the idea of ENDP is to implement the following:

(decliam (inline endp))
(defun endp (x)
(cond ((null x) t)
((consp x) nil)
((running-in-high-safety-p)
(error "Don't expect me to waste space inlining this test in production code."))
(t '*if-you-get-here-you-deserve-to-lose*)))

If it means more than this, I don't know what.

Personally, I have never used ENDP either because my understanding of it
is too impoverished to let me use it properly or because my value
system is such that what it does is not of interest to me. I know which
of these I believe is my reason, but my belief might be ill-founded. :-)


> in any case, if it does not signal an error, it should definitely return
> true for any non-cons object.

Uh, no. As I understand it, it should definitely return false for any
cons. What it does for non-conses is very much dependent on safety
unless you're using proper lists.

Simon Leinen

unread,
Feb 15, 1999, 3:00:00 AM2/15/99
to
>>>>> "kmp" == Kent M Pitman <pit...@world.std.com> writes:
> Personally, I have never used ENDP either because my understanding
> of it is too impoverished to let me use it properly or because my
> value system is such that what it does is not of interest to me. I
> know which of these I believe is my reason, but my belief might be
> ill-founded. :-)

Well, I like ENDP and use it a lot - it gives me warm fuzzies because
- it "should" do the right (error-checking) thing during debugging
- it "should" do the right (efficient) thing with high optimization
- it's makes the intention clearer to the reader than NULL or ATOM or
EQ...'()

With "should" I guess I mean: it's permitted by the spec and it's what
I would expect from a good implementation (and if it isn't implemented
that way, it's no catastrophe either).
--
Simon.

SLong

unread,
Feb 15, 1999, 3:00:00 AM2/15/99
to
Sometimes the penalty of verbosity pays is not so great as the confusion
of obfuscation.

slong

(defun every-other
(list-in
&key (start 0)
)
(if (listp list-in)
(do* ((theList (if (listp list-in) list-in (list list-in)))
(limit (- (length theList) 1))
(n start (+ n 2))
(elements-out nil)
)
((> n limit) (return (reverse elements-out)))
(push (nth n theList) elements-out)
)
nil
)
)

0 new messages