From: eugene kim
Subject: newbie question
Date: 
Message-ID: <ab2cm0$vih$1@newsreader.mailgate.org>
hi all..

i'm trying to make a function which returns list of 3 numbers
it's recursive and it modifies using "setf" the list when neccessary at 
each recursion step



problem is when even though i define the list locally..as (0 0 0)
next time when i call the function again, the function use the result of 
previous call..

is there any other way i can manipulate a list inside function not 
affecting not affecting next call to the same function?

thank you..


here's my code
------------------------------------
guess-num-sexes-friends is function which a user will use.
this function calls guess-num-sexes-friends-internal

(guess-num-sexes-friends user3)

----------------------------------

(defun guess-num-sexes-friends (user)
  ( let ((friends (getAttribute user 'friends)))
    ( guess-num-sexes-friends-internal friends '(0 0 0))))

(defun guess-num-sexes-friends-internal (friends aList)
  (print aList)
  (cond ((null friends) '(0 0 0))
        ((> (guessSex-num (first friends)) 0)
         (setf (first aList) (+ 1 (first (guess-num-sexes-friends-internal 
(rest friends) aList)))) aList)
        ((< (guessSex-num (first friends)) 0)
         (setf (second aList) (- (second (guess-num-sexes-friends-internal 
(rest friends) aList)) 1)) aList)
        (t (setf (third aList) (+ 1 (third 
(guess-num-sexes-friends-internal (rest friends) aList))))
aList)))

-------------------------------------------



here r all functions and definitions related to the problem

exercise problem in this site
http://grimpeur.tamu.edu/~colin/lp/node57.html

--------------------------------------------

(defstruct user
  firstName
  lastName
  address
  age
  sex
  martial-status
  friends)


(setf userDB nil)

(setf user1 (make-user
             :firstName 'eugene
             :lastName 'kim
             :address 'cottonwood
             :age 25
             :martial-status 'single
             :sex 'male
             :friends '(david)))
(setf user2 (make-user
             :firstName 'jeehee
             :lastName 'hong
             :address 'south
             :age 23
             :sex 'female
             :martial-status 'single
             :friends '(yoonhee)))
(setf user3 (make-user
             :firstName 'david
             :lastName 'Rhee
             :address 'somewhere
             :age 24
             :sex 'male
             :martial-status 'single
             :friends '(eugene)))
(setf user4 (make-user
             :firstName 'eugene
             :lastName 'kim
             :address 'cottonwood
             :age 12
             :martial-status 'single
             :sex 'female
             :friends '(sohyun)))


(setf userDB (cons user1 userDB))
(setf userDB (cons user2 userDB))
(setf userDB (cons user3 userDB))
(setf userDB (cons user4 userDB))



(defun getAttribute (aUser  user-attribute)
  (cond ((equal user-attribute 'lastName)
         (user-lastName aUser))
        ((equal user-attribute 'firstName)
         (user-firstName aUser))
        ((equal user-attribute 'sex)
         (user-sex aUser))
        ((equal user-attribute 'friends)
         (user-friends aUser))))


(defun getUsers (firstName)
  (getUsers-db firstName userDB))

(defun getUsers-db (firstName userList)
  (cond ( (null userList) nil)
        ( t (let ( (firstUserName (user-firstName (first userList))))
             (cond ( (equal firstUserName firstName)
                     (cons (first userList) (getUsers-db firstName (rest 
userList))))
                   ( t (getUsers-db firstName (rest userList))))))))


(defun addFriend (user friendName)
  (addFriend-db user friendName userDB))

(defun addFriend-db (user friendName userList)
  (cond ( (null userList) nil)
        ( t (let ( ( firstUser (first userList)))
              (cond ( (equal firstUser user)
                      (if (atom (user-friends user))
                          (cons friendName (list (user-friends user)))
                        (cons friendName (user-friends user))))
                    ( t (setf (user-friends user) (addFriend-db user 
friendName (rest userList)))))))))

(addFriend user1 'james)

(defun num-friends (user)
  (num-friends-db user userDB))
(defun num-friends-db (user userList)
  (cond ( ( null userList) nil)
        ( t (let (( firstUser (first userList)))
              (cond ( ( equal firstUser user)
;                      (if (atom (user-friends user))
;                          1
                        (length (user-friends user)))
                    (t (num-friends-db user (rest userList))))))))

(defun guessSex (firstName)
  (let  ((sex (guessSex-internal (getUsers firstName))))
    (cond ( (> sex 0)
          'male)
          ( (< sex 0)
            'female)
          ( t 'either))))

(defun guessSex-num (firstName)
  (guessSex-internal (getUsers firstName)))

(defun guessSex-internal (userList)
  ( cond ((null userList) 0)
         ((equal 'male (getAttribute (first userList) 'sex))
          (+ 1 (guessSex-internal (rest userList))))
         (t (- (guessSex-internal (rest userList)) 1))))
    


(defun guess-num-sexes-friends (user)
  ( let ((friends (getAttribute user 'friends)))
    ( guess-num-sexes-friends-internal friends '(0 0 0))))

(defun guess-num-sexes-friends-internal (friends aList)
  (print aList)
  (cond ((null friends) '(0 0 0))
        ((> (guessSex-num (first friends)) 0)
         (setf (first aList) (+ 1 (first (guess-num-sexes-friends-internal 
(rest friends) aList)))) aList)
        ((< (guessSex-num (first friends)) 0)
         (setf (second aList) (- (second (guess-num-sexes-friends-internal 
(rest friends) aList)) 1)) aList)
        (t (setf (third aList) (+ 1 (third 
(guess-num-sexes-friends-internal (rest friends) aList))))
aList)))


(addfriend user3 'david)
(addfriend user3 'jeehee)
(guess-num-sexes-friends user3)

From: ·······@andrew.cmu.edu
Subject: Re: newbie question
Date: 
Message-ID: <20020505020752.D3846@emu>
A few quick tips: '(0 0 0) technically creates an immutable object and
the consequences of modifying it are undefined.  Also, why are you
using setf here anyway?  It appears quite unnecessary to modify the
argument when you should simply be returning a newly constructed value.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Kenny Tilton
Subject: Re: newbie question
Date: 
Message-ID: <3CD4CFC4.ABCE7374@nyc.rr.com>
eugene kim wrote:
> 
> hi all..
> 
> i'm trying to make a function which returns list of 3 numbers
> it's recursive and it modifies using "setf" the list when neccessary at
> each recursion step
> 
> problem is when even though i define the list locally..as (0 0 0)

Well, it's local but it's a literal. if you know "c" this is like
modifying:

   char *howdy = "Howdy!!!";

I did not look at your code since the symptom you describe seems to fit
my guess that by using the literal '(0 0 0) you simply /are/ working on
the same list each time.

Try (list 0 0 0) instead. That ensures a new list.

Once that works, you might reconsider whether recursion adds any value
over dolist, and whether you cannot just track three local values and
then return a list of them as the final step.

(defun guess-num-sexes-friends (user)
  ( let ((friends (getAttribute user 'friends)))
    ( guess-num-sexes-friends-internal friends (list 0 0 0))))

(defun guess-num-sexes-friends-internal (friends aList)
  (print aList)
  (cond ((null friends) (list 0 0 0)) ;; why another list?
        ((> (guessSex-num (first friends)) 0)
         (setf (first aList) (+ 1 (first
(guess-num-sexes-friends-internal 
                                          (rest friends) aList))))
         aList)
        ((< (guessSex-num (first friends)) 0)
         (setf (second aList) (- (second
(guess-num-sexes-friends-internal 
                                          (rest friends) aList)) 1))
         aList)
        (t (setf (third aList) (+ 1 (third
(guess-num-sexes-friends-internal (rest friends) aList))))
           aList)))

; that's not really recursion in any interesting sense, you could just
as well code:

(defun guess-num-sexes-friends (user)
  ( let ((alist (list 0 0 0))
         (friends (getAttribute user 'friends)))
    ( guess-num-sexes-friends-internal friends alist)))

(defun guess-num-sexes-friends-internal (friends aList)
  (when friends
    (print aList)
    (guess-num-sexes-friends-internal (rest friends) aList) ;; throw
away return value without effect

    (cond ((> (guessSex-num (first friends)) 0)
           (setf (first aList) (+ 1 (first aList))))
          ((< (guessSex-num (first friends)) 0)
           (setf (second aList) (- (second alist) 1)))
          (t (setf (third aList) (+ 1 (third alist)))))

    (values))) ;; just to make a point that the return value does not
matter as you have things

; do you know about minusp, plusp, incf, decf?...

(defun guess-num-sexes-friends-internal (friends aList)
  (when friends
    (print aList)

    (guess-num-sexes-friends-internal (rest friends) aList)

    (cond ((plusp (guessSex-num (first friends)))
           (incf (first aList)))

          ((minusp (guessSex-num (first friends)))
           (decf (second aList)))
          
          (t (incf (third aList)))))

  (values))

; one good thing about lisp is not having to make separate helper
functions:

(defun guess-num-sexes-friends (user)
  (let ((alist (list 0 0 0)))
    (dolist (friend (getAttribute user 'friends) alist)
      (print aList)
      (cond ((plusp (guessSex-num friend))
             (incf (first aList)))
            
            ((minusp (guessSex-num friend))
             (decf (second aList)))

            (t (incf (third aList)))))))

;; finally, this is clearer:

(defun guess-num-sexes-friends (user)
  (let ((sex+ 0) (sex- 0) (sex0 0))
    (dolist (friend (getAttribute user 'friends) (list sex+ sex- sex0))
      (print aList)
      (cond ((plusp (guessSex-num friend)) (incf sex+))
            ((minusp (guessSex-num friend)) (decf sex-))
            (t (incf sex0))))))

-- 

 kenny tilton
 clinisys, inc
 ---------------------------------------------------------------
"Harvey has overcome not only time and space but any objections."
                                                        Elwood P. Dowd
From: eugene kim
Subject: Re: newbie question
Date: 
Message-ID: <ab2pv6$2eg$1@newsreader.mailgate.org>
mdanish thank you
thank you kenny again..

well,
final is next week, i'm not taking class about lisp
i'm just trying to grasp simple syntax first..
however, i'll look through your kind answer carefully whenever i have  
time..

thank you again.
From: eugene kim
Subject: Re: newbie question
Date: 
Message-ID: <ab2t5b$3cm$1@newsreader.mailgate.org>
hi kenny

i'm actually going over your corrections..
however your corrections r not giving correct outputs..
probably because u just assumed what my functions do without looking at 
them.
i'm having trouble with understanding your code(which i want to learn!)
it would be very nice if u can show me a correct way again.



you can just copy-paste and evaluate region..
output of last expression should be (2 -3 1)
-------------------

(defstruct user
  firstName
  lastName
  address
  age
  sex
  martial-status
  friends)


(setf userDB nil)
(defun addUser (aUser)
  (setf aUser (make-user))
  (setf userDB (cons aUser userDB)))

(defun removeUser (aUser)
  (setf userDB (removeUser-db aUser userDB)))

(defun removeUser-db (aUser userList)
  (let ( ( firstUser (first userList)))
    (cond ( (null userList) nil)
          ( (equal firstUser aUser)
            ( removeUser-db aUser (rest userList)))
          ( t ( cons firstUser (removeUser-db aUser (rest userList)))))))



(setf user1 (make-user
             :firstName 'eugene
             :lastName 'kim
             :address 'cottonwood
             :age 25
             :martial-status 'single
             :sex 'male
             :friends '(david)))
(setf user2 (make-user
             :firstName 'jeehee
             :lastName 'hong
             :address 'south
             :age 23
             :sex 'female
             :martial-status 'single
             :friends '(yoonhee)))
(setf user3 (make-user
             :firstName 'david
             :lastName 'Rhee
             :address 'somewhere
             :age 24
             :sex 'male
             :martial-status 'single
             :friends '(eugene)))
(setf user4 (make-user
             :firstName 'eugene
             :lastName 'kim
             :address 'cottonwood
             :age 12
             :martial-status 'single
             :sex 'female
             :friends '(sohyun)))

(setf userDB (cons user1 userDB))
(setf userDB (cons user2 userDB))
(setf userDB (cons user3 userDB))
(setf userDB (cons user4 userDB))

;(removeUser user1)



(defun setFirstName (aUser firstName)
  (setf (user-firstName aUser) firstName))

(defun getAttribute (aUser  user-attribute)
  (cond ((equal user-attribute 'lastName)
         (user-lastName aUser))
        ((equal user-attribute 'firstName)
         (user-firstName aUser))
        ((equal user-attribute 'sex)
         (user-sex aUser))
        ((equal user-attribute 'friends)
         (user-friends aUser))))


(getAttribute user2 'friends)


(defun getUsers (firstName)
  (getUsers-db firstName userDB))

(defun getUsers-db (firstName userList)
  (cond ( (null userList) nil)
        ( t (let ( (firstUserName (user-firstName (first userList))))
             (cond ( (equal firstUserName firstName)
                     (cons (first userList) (getUsers-db firstName (rest 
userList))))
                   ( t (getUsers-db firstName (rest userList))))))))


(defun addFriend (user friendName)
  (addFriend-db user friendName userDB))

(defun addFriend-db (user friendName userList)
  (cond ( (null userList) nil)
        ( t (let ( ( firstUser (first userList)))
              (cond ( (equal firstUser user)
                      (setf (user-friends user) (cons friendName 
(user-friends user))))
                    ( t  (addFriend-db user friendName (rest 
userList))))))))


(defun num-friends (user)
  (num-friends-db user userDB))
(defun num-friends-db (user userList)
  (cond ( ( null userList) nil)
        ( t (let (( firstUser (first userList)))
              (cond ( ( equal firstUser user)
                      (length (user-friends user)))
                    (t (num-friends-db user (rest userList))))))))

(defun guessSex (firstName)
  (let  ((sex (guessSex-internal (getUsers firstName))))
    (cond ( (> sex 0)
          'male)
          ( (< sex 0)
            'female)
          ( t 'either))))

(defun guessSex-num (firstName)
  (guessSex-internal (getUsers firstName)))

(defun guessSex-internal (userList)
  ( cond ((null userList) 0)
         ((equal 'male (getAttribute (first userList) 'sex))
          (+ 1 (guessSex-internal (rest userList))))
         (t (- (guessSex-internal (rest userList)) 1))))

(defun guess-num-sexes-friends (user)
  ( let ((friends (getAttribute user 'friends)))
    ( guess-num-sexes-friends-internal friends (list 0 0 0))))

(defun guess-num-sexes-friends-internal (friends aList)
  (cond ((null friends) aList)
        ((> (guessSex-num (first friends)) 0)
         (setf (first aList) (+ 1 (first (guess-num-sexes-friends-internal 
(rest friends) aList)))) aList)
        ((< (guessSex-num (first friends)) 0)
         (setf (second aList) (- (second (guess-num-sexes-friends-internal 
(rest friends) aList)) 1)) aList)
        (t (setf (third aList) (+ 1 (third 
(guess-num-sexes-friends-internal (rest friends) aList))))
aList)))

(addfriend user3 'david)
(addfriend user3 'david)
(addfriend user3 'jeehee)
(addfriend user3 'jeehee)
(addfriend user3 'jeehee)
(guess-num-sexes-friends user3);;(2 -3 1) == (num of male, num of female, 
num of non-guessable)
------------------------------------------------------
From: Kenny Tilton
Subject: Re: newbie question
Date: 
Message-ID: <3CD54890.65753E04@nyc.rr.com>
hey, eugene...

sorry, i almost added the caveat "completely untested", but got lazy and
left it out.

corrected:

(defun guess-num-sexes-friends (user)
  (let ((sex+ 0) (sex- 0) (sex0 0))
    (dolist (friend (getAttribute user 'friends) (list sex+ sex- sex0))
      ;;; (print aList) <======== left in inadvertently while hacking
away at your version
      (cond ((plusp (guessSex-num friend)) (incf sex+))
            ((minusp (guessSex-num friend)) (decf sex-))
            (t (incf sex0))))))

...that (print aList) is just a debugging line left over from your
version. Take it out and all is well.

As for understanding the code, observe that (INCF <place>) is like (SETF
<place> (+ 1 <place>) and that (> <any> 0) can be coded (plusp <any>).

btw, if you really want to start with a list or you really want to use
recursion, here are some other approaches (tested) to look at:

(defun gnsf (user)
  (labels ((gnsfi (friends)
              (if (null friends)
                  (list 0 0 0)
                (let ((resulti (gnsfi (rest friends)))
                      (this-guess (guessSex-num (first friends))))
                  (cond ((plusp this-guess) (incf (first resulti)))
                        ((minusp this-guess) (decf (second resulti)))
                        (t (incf (third resulti))))
                  resulti))))
    (gnsfi (getAttribute user 'friends))))

(defun gnsf2 (user)
  (let ((result (list 0 0 0)))
    (mapc (lambda (friend)
            (let ((this-guess (guessSex-num friend)))
              (cond ((plusp this-guess) (incf (first result)))
                    ((minusp this-guess) (decf (second result)))
                    (t (incf (third result))))))
      (getAttribute user 'friends))
    result))


-- 

 kenny tilton
 clinisys, inc
 ---------------------------------------------------------------
"Harvey has overcome not only time and space but any objections."
                                                        Elwood P. Dowd