From: Martin J. Zaidel
Subject: Elegant control structure wanted
Date: 
Message-ID: <98373@netnews.upenn.edu>
I've written an equality predicate to test two structures.  My
predicate is of the form:

(defun node-equal (node1 node2)
   (and (slot1-equal slot1 slot2)
	(slot2-equal slot1 slot2)
	(slot3-equal slot1 slot2)))

(Actually, the two node arguments have vastly different structures, but 
that's not the issue here.)

I wanted to add format statements so that when NODE-EQUAL returned nil,
I'd know which slot caused the failure.  So I tried UNLESS:

(defun node-equal (node1 node2)
   (and (unless (slot1-equal slot1 slot2)
	   (format t "Slot 1 not equal"))
	(unless (slot2-equal slot1 slot2)
	   (format t "Slot 2 not equal"))
	(unless (slot3-equal slot1 slot2)
	   (format t "Slot 3 not equal"))))

This won't work, since UNLESS will return NIL, regardless of the 
value of the slot-equal test.  Now, CLtL2 p.158 advises that, when the 
value of the unless is relevant (as it is here), to use IF instead.

That means my code is:

(defun node-equal (node1 node2)
   (and (if (slot1-equal slot1 slot2) 
	    t
	    (format t "Slot 1 not equal"))
	(if (slot2-equal slot1 slot2)
	    t
	    (format t "Slot 2 not equal"))
	(if (slot3-equal slot1 slot2)
	    t
	    (format t "Slot 3 not equal"))))

This explicit use of T for the value of the IF strikes me as rather
inelegant.  I'd appreciate suggestions for a nicer solution.

Thanks in advance.

From: Joe Konstan
Subject: Re: Elegant control structure wanted
Date: 
Message-ID: <1992Nov19.182342.17095@news2.cis.umn.edu>
In article <·····@netnews.upenn.edu>, ······@muzungu.cis.upenn.edu (Martin J. Zaidel) is trying to modify
|> (defun node-equal (node1 node2)
|>    (and (slot1-equal slot1 slot2)
|> 	(slot2-equal slot1 slot2)
|> 	(slot3-equal slot1 slot2)))
to add format statements to show which slot triggered the inequality.

It seems to me that you have two choices, each of which could add a
bit of elegance.  First, if you are willing to modify slot-1-equal, ..., 
I would suggest putting the format in there (possibly controlled by
an optional parameter):

	(defun slot1-equal (x y &optional (fmt? nil))
          ...)

If this is inappropriate, then I'd go back to basics and use cond.  Recall
that format always returns nil (except for (format nil ...), p 581 CLtL2), so:

	(defun node-equal (node1 node2)
          (cond ((not (slot1-equal node1 node2)) (format t "Slot 1"))
                ((not (slot2-equal node1 node2)) (format t "Slot 2"))
                (t t)))

Another choice to consider is not using format at all, but instead trying one
of the following:

1.  Use values to return multiple values--namely t or nil and when nil the
    slot that failed.

2.  Write the inverse

	(defun difference (node1 node2)
	....

    so that it returns nil when they are equal and the slot name when they 
    aren't.


Joe Konstan
·······@cs.umn.edu
From: Raymond K. Fink
Subject: Re: Elegant control structure wanted
Date: 
Message-ID: <1992Nov19.200850.11967@inel.gov>
······@muzungu.cis.upenn.edu (Martin J. Zaidel) writes:
>I've written an equality predicate to test two structures.  My
>predicate is of the form:
>
>(defun node-equal (node1 node2)
>   (and (slot1-equal slot1 slot2)
>	(slot2-equal slot1 slot2)
>	(slot3-equal slot1 slot2)))
>
>I wanted to add format statements so that when NODE-EQUAL returned nil,
>I'd know which slot caused the failure.  So I tried UNLESS:
...
>inelegant.  I'd appreciate suggestions for a nicer solution.

My suggestion, using the fact that (format ....) returns nil

(defparameter *node-equality-tests*
  '(slot1-equal slot2-equal slot3-equal))

(defun node-equal (node1 node2)
  ;; apply test functions in sequence, returning t if completed ok
  (dolist (fn *node-equality-tests* t)
    (unless (funcall fn node1 node2)
       ;; up and out if a test fails, returning nil and logging message
       (return (format t "Failed on ~A" fn)))))

Pro: easy to modify the list of tests without changing the test function
Con: may be slower and cons'ier than desirable

--
Ray Fink -- Idaho National Engineering Laboratory -- Idaho Falls ID 
	···@inel.gov			208-525-5431
Hit 'n' now to skip the obnoxious legal disclaimer......
========== long legal disclaimer follows, press n to skip ===========

Neither the United States Government or the Idaho National Engineering
Laboratory or any of their employees, makes any warranty, whatsoever,
implied, or assumes any legal liability or responsibility regarding any
information, disclosed, or represents that its use would not infringe
privately owned rights.  No specific reference constitutes or implies
endorsement, recommendation, or favoring by the United States
Government or the Idaho National Engineering Laboratory.  The views and
opinions expressed herein do not necessarily reflect those of the
United States Government or the Idaho National Engineering Laboratory,
and shall not be used for advertising or product endorsement purposes.
From: Barry Margolin
Subject: Re: Elegant control structure wanted
Date: 
Message-ID: <1eh16rINNl8i@early-bird.think.com>
In article <·····@netnews.upenn.edu> ······@muzungu.cis.upenn.edu (Martin J. Zaidel) writes:
>(defun node-equal (node1 node2)
>   (and (unless (slot1-equal slot1 slot2)
>	    (format t "Slot 1 not equal"))
>	 (unless (slot2-equal slot1 slot2)
>	    (format t "Slot 2 not equal"))
>	 (unless (slot3-equal slot1 slot2)
>	    (format t "Slot 3 not equal"))))
>
>This won't work, since UNLESS will return NIL, regardless of the 
>value of the slot-equal test.  

You can use OR instead of UNLESS; in fact, this is what people did all the
time before UNLESS was introduced.  The code then becomes

(defun node-equal (node1 node2)
  (and (or (slot1-equal node1 node2)
	   (format t "~&Slot 1 not equal.~%"))
       (or (slot2-equal node1 node2)
	   (format t "~&Slot 1 not equal.~%"))
       (or (slot3-equal node1 node2)
	   (format t "~&Slot 1 not equal.~%"))))

Actually, I prefer not to depend on the return value of FORMAT being NIL
(because I don't remember whether such return values are guaranteed), so
I'd probably write something like:

(defun node-equal (node1 node2)
  (and (or (slot1-equal node1 node2)
	   (progn (format t "~&Slot 1 not equal.~%")
                  nil))
       (or (slot2-equal node1 node2)
	   (progn (format t "~&Slot 1 not equal.~%")
                  nil))
       (or (slot3-equal node1 node2)
	   (progn (format t "~&Slot 1 not equal.~%")
                  nil))))

And now that the code is starting to look messy and repetitive, I'd
probably turn the repetitive code into a local macro:

(defun node-equal (node1 node2)
  (macrolet ((compare (tester slot-number)
               `(or (,tester node1 node2)
                    (progn (format t "~&Slot ~D not equal.~%" ,slot-number)
                           nil))))
    (and (compare slot1-equal 1)
         (compare slot2-equal 2)
         (compare slot3-equal 3))))
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Len Charest
Subject: Re: Elegant control structure wanted
Date: 
Message-ID: <1992Nov19.223154.4885@jpl-devvax.jpl.nasa.gov>
In article <·····@netnews.upenn.edu>, ······@muzungu.cis.upenn.edu (Martin J. Zaidel) writes:
|> I've written an equality predicate to test two structures.  My
|> predicate is of the form:

|> (defun node-equal (node1 node2)
|>    (and (if (slot1-equal slot1 slot2) 
|> 	    t
|> 	    (format t "Slot 1 not equal"))
|> 	(if (slot2-equal slot1 slot2)
|> 	    t
|> 	    (format t "Slot 2 not equal"))
|> 	(if (slot3-equal slot1 slot2)
|> 	    t
|> 	    (format t "Slot 3 not equal"))))
|> 
|> This explicit use of T for the value of the IF strikes me as rather
|> inelegant.  I'd appreciate suggestions for a nicer solution.

Did you mean to write 'node1' and 'node2' instead of 'slot1' and 'slot2'?
Relying on the fact that FORMAT returns NIL:

(defun node-equal (node1 node2)
  (and (or (slot1-equal node1 node2)
           (format t "..."))
       ...and so on ))
..................................................
                                  Len Charest, Jr.
                 JPL Artificial Intelligence Group
                          ·······@aig.jpl.nasa.gov