Page 1 of 2
Why does taking out nil break this code segment?
Posted: Thu Jan 21, 2010 1:26 pm
by yougene
Code: Select all
(defun our-member (obj lst)
(if (null lst)
nil
(if (eql (car lst) obj)
lst
(our-member obj (cdr lst)))))
Taking out the nil breaks the code. Why?
Re: Why does taking out nil break this code segment?
Posted: Thu Jan 21, 2010 2:51 pm
by ramarren
Generally randomly reversing the meaning of conditional expressions will break things. If you do not understand what
IF does then I would suggest going back to
the basics.
Re: Why does taking out nil break this code segment?
Posted: Thu Jan 21, 2010 3:51 pm
by gugamilare
yougene wrote:Code: Select all
(defun our-member (obj lst)
(if (null lst)
nil
(if (eql (car lst) obj)
lst
(our-member obj (cdr lst)))))
Taking out the nil breaks the code. Why?
Nil is the default value returned if the list is empty, that is why it is there. If you remove it, the last
if is evaluated only when the list is empty, which won't work.
Re: Why does taking out nil break this code segment?
Posted: Fri Jan 22, 2010 1:01 pm
by yougene
I guess my question is why are the two if statements nested?
If the first IF is true and it returns nil how can it go on to evaluate the second IF?
Re: Why does taking out nil break this code segment?
Posted: Fri Jan 22, 2010 1:07 pm
by yougene
I think I found my answer
(if < condition-form >
< then-form >
< else-form >)
Does this mean that the last line is always assumed to be the command for "else"?
Re: Why does taking out nil break this code segment?
Posted: Fri Jan 22, 2010 1:48 pm
by ramarren
yougene wrote:Does this mean that the last line is always assumed to be the command for "else"?
It is not a line, it is a form, and not a command but a possibly side effecting expression. This is not just semantics, understanding the meaning of these words is crucial to understanding Lisp. And no, if the IF form has only two arguments then the second one, which will in that case be last, would be a "then" expression, and the else branch would be an implicit NIL. When you removed the NIL in your original post you effectively exchanged the branches.
Seriously, questions at this level are best answered as part of comprehensive text like the one I linked earlier or
Practical Common Lisp. Guessing at syntax and semantics of a language rarely ends well.
Re: Why does taking out nil break this code segment?
Posted: Sat Jan 23, 2010 4:15 pm
by hewih
in
if you can only have 1 form for
then and 1 form for
else. the other way around, how would Lisp know which form belongs to
then and which to
else
Code: Select all
(if (null lst)
(format T "then")
(format T "else")
)
(if (null lst)
(format T "then")
(format T "else")
(format T "umm...?") ; <= not working!!!
)
if you only need the
then or
else, use
when or
unless
Code: Select all
(when (null lst)
(format T "statement1")
(format T "statement2")
(format T "statement3")
)
if you need more statements in
then or
else, use
progn
Code: Select all
(if (null lst)
(progn ; encapsulates the whole then block
(format T "statement1")
(format T "statement2")
(format T "statement3")
)
(format T "else")
)
Re: Why does taking out nil break this code segment?
Posted: Sat Jan 23, 2010 4:46 pm
by ramarren
hewih wrote:in if you can only have 1 form for then and 1 form for else. the other way around, how would Lisp know which form belongs to then and which to else
That is true for Common Lisp, but for example in Emacs Lisp all forms after the second form an implicit PROGN for the else clause. Some people even use an IF* macro like this in CL, although I don't really think this is all that useful.
hewih wrote:if you need more statements in then or else, use progn
Even better, use
COND. This is of course subjective, but I don't think I am alone in thinking that is clearer, even for just two branches.
Re: Why does taking out nil break this code segment?
Posted: Sun Jan 24, 2010 12:37 pm
by krz
I'd like to amplify the previous comment.
In Common Lisp, nested
if expressions can often be rewritten as a single
cond, and it's generally considered good style to do so.
For example, you posted
Code: Select all
(defun our-member (obj lst)
(if (null lst)
nil
(if (eql (car lst) obj)
lst
(our-member obj (cdr lst)))))
Which could be expressed more clearly (that is, less nesting) as the following. Generally, the deeper the nesting of your
if statements, the clearer they get when you rewrite them into
cond form.
Code: Select all
(defun our-member (obj lst)
(cond
((null lst)
nil)
((eql (car lst) obj)
lst)
(t
(our-member obj (cdr lst)))))
Some folks would, given simple expressions like these, run the clauses together on the same line. It's bad for intricate expressions, but passable with simple stuff like this.
Code: Select all
(defun our-member (obj lst)
(cond
((null lst) nil)
((eql (car lst) obj) lst)
(t (our-member obj (cdr lst)))))
Re: Why does taking out nil break this code segment?
Posted: Sat Jan 30, 2010 4:45 am
by wentbackward
IF has a true part and false part. Taking out nil will mean the false part becomes the true part. But yes the first
IF could be replaced by something simpler.
Code: Select all
(defun our-member (obj lst)
(unless (null lst)
(if (eql (car lst) obj)
lst
(our-member obj (cdr lst)))))
Would still return nil if lst was nil. The cond suggestion is probably better.