Why does taking out nil break this code segment?

Discussion of Common Lisp

Why does taking out nil break this code segment?

Postby yougene » Thu Jan 21, 2010 1:26 pm

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?
yougene
 
Posts: 23
Joined: Thu Jan 21, 2010 1:23 pm

Re: Why does taking out nil break this code segment?

Postby Ramarren » Thu Jan 21, 2010 2:51 pm

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.
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: Why does taking out nil break this code segment?

Postby gugamilare » Thu Jan 21, 2010 3:51 pm

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.
gugamilare
 
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil

Re: Why does taking out nil break this code segment?

Postby yougene » Fri Jan 22, 2010 1:01 pm

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?
yougene
 
Posts: 23
Joined: Thu Jan 21, 2010 1:23 pm

Re: Why does taking out nil break this code segment?

Postby yougene » Fri Jan 22, 2010 1:07 pm

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"?
yougene
 
Posts: 23
Joined: Thu Jan 21, 2010 1:23 pm

Re: Why does taking out nil break this code segment?

Postby Ramarren » Fri Jan 22, 2010 1:48 pm

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.
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: Why does taking out nil break this code segment?

Postby hewih » Sat Jan 23, 2010 4:15 pm

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")
)
User avatar
hewih
 
Posts: 30
Joined: Tue Jan 19, 2010 9:36 am

Re: Why does taking out nil break this code segment?

Postby Ramarren » Sat Jan 23, 2010 4:46 pm

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.
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: Why does taking out nil break this code segment?

Postby krz » Sun Jan 24, 2010 12:37 pm

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)))))
krz
 
Posts: 2
Joined: Sun Jan 24, 2010 10:57 am
Location: Rochester, New York, USA

Re: Why does taking out nil break this code segment?

Postby wentbackward » Sat Jan 30, 2010 4:45 am

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.
wentbackward
 
Posts: 2
Joined: Sat Jan 30, 2010 4:08 am

Next

Return to Common Lisp

Who is online

Users browsing this forum: Google [Bot], logxor and 2 guests