From: Jordan Katz
Subject: newbie question.
Date: 
Message-ID: <m3y9hswznc.fsf@underlevel.underlevel.net>
Hello,

  I was in the process of learning Lisp (I'm using ANSI Common Lisp as
my guide) but I stopped for a few months and now am trying to relearn
it.  I was a beginner before, but now even the simple exercises from
Graham's book puzzle me.  I tried solving the following exercises,
from one of the early chapters, that asks to write a union function
that maintains the order of lists.  I came up with the following
"pseudo-code":

  1.  iterate through two lists, a and b.
  2.  if both are null, return nil.
  3.  store every element of a and b in a third list, c, unless:
        - a is a member of c already
        - or b is a member of c already
  4.  take the cdr of a and cdr of b and continue.

My pseudo code, although probably horribly imperative and
non-functional, seems correct to me.  I tried implementing it:

(defun union-helper (a b c)
  (if (and (null a) (null b))
      nil
      (progn
        (if (not (member (car a) c))
            (setf c (cons (car a) c)))
        (if (not (member (car b) c))
            (setf c (cons (car b) c)))
        (union-helper (cdr a) (cdr b) c))))

(defun union (a b)
  (union-helper a b '()))

But it returns nil all the time.  It also seems to be, though I may be
wrong, that such a simple function can really be written with out a
helper.  Could someone point out to me what I did wrong in my
function, and what the typical way (but still recursive because that's
the method I'm really trying to learn as a beginner) to do it would
be?  I appreciate all the help.

Thanks a lot,
(P.S. I take no CS or Lisp related classes, this is for my own study.)
-- 
Jordan Katz <····@underlevel.net>  |  Mind the gap

From: Nils Goesche
Subject: Re: newbie question.
Date: 
Message-ID: <3c6f1ed5$1_4@news2.uncensored-news.com>
In article <··············@underlevel.underlevel.net>, Jordan Katz wrote:
> Hello,
> 
>   I was in the process of learning Lisp (I'm using ANSI Common Lisp as
> my guide) but I stopped for a few months and now am trying to relearn
> it.  I was a beginner before, but now even the simple exercises from
> Graham's book puzzle me.  I tried solving the following exercises,
> from one of the early chapters, that asks to write a union function
> that maintains the order of lists.  I came up with the following
> "pseudo-code":
> 
>   1.  iterate through two lists, a and b.
>   2.  if both are null, return nil.
>   3.  store every element of a and b in a third list, c, unless:
>         - a is a member of c already
>         - or b is a member of c already
>   4.  take the cdr of a and cdr of b and continue.
> 
> My pseudo code, although probably horribly imperative and
> non-functional, seems correct to me.

There is nothing horrible per se about imperative non-functional code.
People who believe that should be programming in Haskell until they
have suffered enough to learn the lesson.

>  I tried implementing it:
> 
> (defun union-helper (a b c)
>   (if (and (null a) (null b))
>       nil
>       (progn
>         (if (not (member (car a) c))
>             (setf c (cons (car a) c)))
>         (if (not (member (car b) c))
>             (setf c (cons (car b) c)))
>         (union-helper (cdr a) (cdr b) c))))
> 
> (defun union (a b)
>   (union-helper a b '()))
> 
> But it returns nil all the time.

That's because you told it to: If both a and b are empty, what do
you return according to the definition of union-helper?

I am sure you see it now; after you have corrected that, you will
see yet another error with the code.  If you can't fix it, come back.

Oh, yes: You were asking how you could avoid the extra function.  You
could use a local function, as in

(defun fac (n)
  (labels ((helper (i acc)
             (if (zerop i)
                 acc
               (helper (1- i) (* acc i)))))
    (helper n 1)))

Note that this is a very stupid way to compute factorials, but you
can see how to use local functions.

Another note:  I used ANSI Common Lisp, too, to get started with
Common Lisp.  From the book I learned that the loop macro
is so extremely hard to use that I decided not to learn it at all.
That was stupid.  I absolutely don't know where Graham got the idea that
there is anything hard to understand about loop.  Just try (he
actually describes how to use it in the book in a way everybody
can understand) and you'll see for yourself.  And don't worry if
``ANSI Common Lisp'' gets boring after a while: The really interesting
stuff is in his other book, ``On Lisp''.

Regards,
-- 
Nils Goesche
Ask not for whom the <CONTROL-G> tolls.

PGP key ID 0x42B32FC9

______________________________________________________________________
Posted Via Uncensored-News.Com - Still Only $9.95 - http://www.uncensored-news.com
   With NINE Servers In California And Texas - The Worlds Uncensored News Source
  
From: Nils Goesche
Subject: Re: newbie question.
Date: 
Message-ID: <3c6f2123$1_4@news2.uncensored-news.com>
In article <············@news2.uncensored-news.com>, Nils Goesche wrote:
> In article <··············@underlevel.underlevel.net>, Jordan Katz wrote:
>> (defun union (a b)
>>   (union-helper a b '()))
>> 
>> But it returns nil all the time.
> 
> That's because you told it to: If both a and b are empty, what do
> you return according to the definition of union-helper?
> 
> I am sure you see it now; after you have corrected that, you will
> see yet another error with the code.  If you can't fix it, come back.

Oh, there is another error I forgot to mention:  IIRC You are not allowed
to redefine symbols exported from the COMMON-LISP package.  So, better
call your function `myunion' or something.

Regards,
-- 
Nils Goesche
Ask not for whom the <CONTROL-G> tolls.

PGP key ID 0x42B32FC9

______________________________________________________________________
Posted Via Uncensored-News.Com - Still Only $9.95 - http://www.uncensored-news.com
   With NINE Servers In California And Texas - The Worlds Uncensored News Source
  
From: Jordan Katz
Subject: Re: newbie question.
Date: 
Message-ID: <m3it8vwuui.fsf@underlevel.underlevel.net>
Nils Goesche <······@cartan.de> writes:

> In article <··············@underlevel.underlevel.net>, Jordan Katz wrote:
> > Hello,
> > 
> >   I was in the process of learning Lisp (I'm using ANSI Common Lisp as
> > my guide) but I stopped for a few months and now am trying to relearn
> > it.  I was a beginner before, but now even the simple exercises from
> > Graham's book puzzle me.  I tried solving the following exercises,
> > from one of the early chapters, that asks to write a union function
> > that maintains the order of lists.  I came up with the following
> > "pseudo-code":
> > 
> >   1.  iterate through two lists, a and b.
> >   2.  if both are null, return nil.
> >   3.  store every element of a and b in a third list, c, unless:
> >         - a is a member of c already
> >         - or b is a member of c already
> >   4.  take the cdr of a and cdr of b and continue.
> > 
> > My pseudo code, although probably horribly imperative and
> > non-functional, seems correct to me.
> 
> There is nothing horrible per se about imperative non-functional code.
> People who believe that should be programming in Haskell until they
> have suffered enough to learn the lesson.
> 
> >  I tried implementing it:
> > 
> > (defun union-helper (a b c)
> >   (if (and (null a) (null b))
> >       nil
> >       (progn
> >         (if (not (member (car a) c))
> >             (setf c (cons (car a) c)))
> >         (if (not (member (car b) c))
> >             (setf c (cons (car b) c)))
> >         (union-helper (cdr a) (cdr b) c))))
> > 
> > (defun union (a b)
> >   (union-helper a b '()))
> > 
> > But it returns nil all the time.
> 
> That's because you told it to: If both a and b are empty, what do
> you return according to the definition of union-helper?
[snip]

Thanks to Nils, David and Martti for the excellent explanations.  My
new function is:

;; exercise 2
(defun union-helper (a b c)
  (if (and (null a) (null b))
      (reverse c)
      (progn
        (if (not (member (car a) c))
            (setf c (cons (car a) c)))
        (if (not (member (car b) c))
            (setf c (cons (car b) c)))
        (union-helper (cdr a) (cdr b) c))))

(defun my-union (a b)
  (union-helper a b '()))

I return the reverse of c in order to have the elements in original
order, as required by the exercise.  Related to this, but probably not
worthy of starting a new thread, is the next exercise in Graham which
I believed I successfully solved.  The task is to construct a
function, occurences, which returns dotted lists of the element and
the amount of times it repeats in a given list in order of most common
to least, e.g. (occurences '(b c b)) => '((b . 2) (c . 1))

My implementations:

(defun occurences (lst)
  (occurences-helper lst '()))

(defun occurences-helper (lst occur-lst)
  (cond ((null lst) occur-lst)
        ((if (member (first lst) (mapcar #'first occur-lst))
             (let ((n (cdr (assoc (first lst) occur-lst))))
                (occurences-helper
                (cdr lst) (cons (cons (first lst) (+ 1 n))
                                (assoc-remove (first lst) occur-lst))))
             (occurences-helper
              (cdr lst) (cons (cons (first lst) 1) occur-lst))))))

(defun assoc-remove (item lst)
  (if (null lst)
      nil
      (if (equal item (first (first lst)))
          (assoc-remove item (cdr lst))
          (cons (first lst) (assoc-remove item (cdr lst))))))

This works with my tests.  It returns the right results AFAIK.  I
don't mean to waste your time with just looking over every answer I
have to an exercise, but this code seems a bit excessive for what
seems to be a simple exercise.  I repeatedly find myself coming up
with solutions that may be clear in terms of the way the problem is
approached, but include so many helper functions and long constructs
that, considering this exercise only appears in ch. 4, I can't help
but think I'm overlooking a much shorter and simpler solution.  Is
that the case for this exercise?

Thanks again, I appreciate your help,
-- 
Jordan Katz <····@underlevel.net>  |  Mind the gap
From: Jim Bushnell
Subject: Re: newbie question.
Date: 
Message-ID: <uxXb8.60796$Ig2.16449683@news1.elcjn1.sdca.home.com>
"Jordan Katz" <····@underlevel.net> wrote in message
···················@underlevel.underlevel.net...
> Nils Goesche <······@cartan.de> writes:
>
> > In article <··············@underlevel.underlevel.net>, Jordan Katz
wrote:
> > > Hello,
> > >
> > >   I was in the process of learning Lisp (I'm using ANSI Common Lisp as
> > > my guide) but I stopped for a few months and now am trying to relearn
> > > it.  I was a beginner before, but now even the simple exercises from
> > > Graham's book puzzle me.  I tried solving the following exercises,
> > > from one of the early chapters, that asks to write a union function
> > > that maintains the order of lists.  I came up with the following
> > > "pseudo-code":
> > >
> > >   1.  iterate through two lists, a and b.
> > >   2.  if both are null, return nil.
> > >   3.  store every element of a and b in a third list, c, unless:
> > >         - a is a member of c already
> > >         - or b is a member of c already
> > >   4.  take the cdr of a and cdr of b and continue.
> > >
> > > My pseudo code, although probably horribly imperative and
> > > non-functional, seems correct to me.
> >
> > There is nothing horrible per se about imperative non-functional code.
> > People who believe that should be programming in Haskell until they
> > have suffered enough to learn the lesson.
> >
> > >  I tried implementing it:
> > >
> > > (defun union-helper (a b c)
> > >   (if (and (null a) (null b))
> > >       nil
> > >       (progn
> > >         (if (not (member (car a) c))
> > >             (setf c (cons (car a) c)))
> > >         (if (not (member (car b) c))
> > >             (setf c (cons (car b) c)))
> > >         (union-helper (cdr a) (cdr b) c))))
> > >
> > > (defun union (a b)
> > >   (union-helper a b '()))
> > >
> > > But it returns nil all the time.
> >
> > That's because you told it to: If both a and b are empty, what do
> > you return according to the definition of union-helper?
> [snip]
>
> Thanks to Nils, David and Martti for the excellent explanations.  My
> new function is:
>
> ;; exercise 2
> (defun union-helper (a b c)
>   (if (and (null a) (null b))
>       (reverse c)
>       (progn
>         (if (not (member (car a) c))
>             (setf c (cons (car a) c)))
>         (if (not (member (car b) c))
>             (setf c (cons (car b) c)))
>         (union-helper (cdr a) (cdr b) c))))
>
> (defun my-union (a b)
>   (union-helper a b '()))
>
> I return the reverse of c in order to have the elements in original
> order, as required by the exercise.  Related to this, but probably not
> worthy of starting a new thread, is the next exercise in Graham which
> I believed I successfully solved.  The task is to construct a
> function, occurences, which returns dotted lists of the element and
> the amount of times it repeats in a given list in order of most common
> to least, e.g. (occurences '(b c b)) => '((b . 2) (c . 1))
>
> My implementations:
>
> (defun occurences (lst)
>   (occurences-helper lst '()))
>
> (defun occurences-helper (lst occur-lst)
>   (cond ((null lst) occur-lst)
>         ((if (member (first lst) (mapcar #'first occur-lst))
>              (let ((n (cdr (assoc (first lst) occur-lst))))
>                 (occurences-helper
>                 (cdr lst) (cons (cons (first lst) (+ 1 n))
>                                 (assoc-remove (first lst) occur-lst))))
>              (occurences-helper
>               (cdr lst) (cons (cons (first lst) 1) occur-lst))))))
>
> (defun assoc-remove (item lst)
>   (if (null lst)
>       nil
>       (if (equal item (first (first lst)))
>           (assoc-remove item (cdr lst))
>           (cons (first lst) (assoc-remove item (cdr lst))))))
>
> This works with my tests.  It returns the right results AFAIK.  I
> don't mean to waste your time with just looking over every answer I
> have to an exercise, but this code seems a bit excessive for what
> seems to be a simple exercise.  I repeatedly find myself coming up
> with solutions that may be clear in terms of the way the problem is
> approached, but include so many helper functions and long constructs
> that, considering this exercise only appears in ch. 4, I can't help
> but think I'm overlooking a much shorter and simpler solution.  Is
> that the case for this exercise?
>
> Thanks again, I appreciate your help,
> --
> Jordan Katz <····@underlevel.net>  |  Mind the gap

Graham wouldn't like this because it uses loop, but it seems to work fine.

(defun occurrences (list)
              (let ((alist nil) (present))
                (loop for item in list
                      if (setq present (assoc item alist)) do
                      (incf (cdr present))
                      else  do (push `(,item . 1) alist)
                      finally return (sort alist #'> :key #'cdr))))

Jim Bushnell
From: Coby Beck
Subject: Re: newbie question.
Date: 
Message-ID: <SS1c8.61099$Cg5.3501311@news1.calgary.shaw.ca>
"Jordan Katz" <····@underlevel.net> wrote in message
···················@underlevel.underlevel.net...
>       (progn
>         (if (not (member (car a) c))
>             (setf c (cons (car a) c)))
>         (if (not (member (car b) c))
>             (setf c (cons (car b) c)))

This is much more succinctly written as:
(progn
    (pushnew (car a) c)
    (pushnew (car b) c))

(pushnew is great :o)

Also style-wise if you have an IF with no else part CL has WHEN and UNLESS
so you can be more clear and write:
(progn
  (unless (member (car a) c)
      (setf c (cons (car a) c)))
  (unless (member (car b) c)
      (setf c (cons (car b) c)))


[snip about the occurences exercise]
> This works with my tests.  It returns the right results AFAIK.  I
> don't mean to waste your time with just looking over every answer I
> have to an exercise, but this code seems a bit excessive for what
> seems to be a simple exercise.  I repeatedly find myself coming up
> with solutions that may be clear in terms of the way the problem is
> approached, but include so many helper functions and long constructs
> that, considering this exercise only appears in ch. 4, I can't help
> but think I'm overlooking a much shorter and simpler solution.  Is
> that the case for this exercise?

Personally, for an iteration problem like this -- traverse the list and do
stuff -- I would use an iterative construct rather than recursion.  I'm sure
you could find something shorter and cleaner with loop or dolist...

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Holger Schauer
Subject: Re: newbie question.
Date: 
Message-ID: <whd6z2oqgf.fsf@ipanema.coling.uni-freiburg.de>
On 17 Feb 2002, Jordan Katz wrote:

> The task is to construct a function, occurences, which returns
> dotted lists of the element and the amount of times it repeats in a
> given list in order of most common to least, e.g. (occurences '(b c
> b)) => '((b . 2) (c . 1))
> 
> (defun occurences-helper (lst occur-lst)
>   (cond ((null lst) occur-lst)
>         ((if (member (first lst) (mapcar #'first occur-lst))
>              (let ((n (cdr (assoc (first lst) occur-lst))))
>                 (occurences-helper
>                 (cdr lst) (cons (cons (first lst) (+ 1 n))
>                                 (assoc-remove (first lst)
>                                 occur-lst))))
>              (occurences-helper
>               (cdr lst) (cons (cons (first lst) 1) occur-lst))))))

> This works with my tests.  It returns the right results AFAIK.  I
> don't mean to waste your time with just looking over every answer I
> have to an exercise, but this code seems a bit excessive for what
> seems to be a simple exercise. 

You should reconsider how you do your counting. It is not necessarily
to modify the whole alist, it's enough to modify the associations.
You'll need to understand the difference between setf and setq and how
that applies to this problem (have a look at section 3.3, page 35).

Holger

-- 
---          http://www.coling.uni-freiburg.de/~schauer/            ---
Fachbegriffe der Informatik - Einfach erkl�rt
142: Microsofties
       ferngesteuerte Marketingdroiden, die immer nur "M�nchen" und
       "Amerika" murmeln k�nnen, wenns kompliziert wird.
       (Martin Schmitt)
From: Matthieu Villeneuve
Subject: Re: newbie question.
Date: 
Message-ID: <3C715784.C6700190@tumbleweed.com>
How about the following code? It doesn't return the exact same result as
Graham's, but the order of the pairs is the only difference, so the
result is valid too.

(defun occurrences (list)
  (let ((occ '()))
    (dolist (elt list)
      (let ((count (assoc elt occ)))
        (if count
            (incf (cdr count))
            (push (cons elt 1) occ))))
    occ))


--Matthieu


Jordan Katz wrote:
> Thanks to Nils, David and Martti for the excellent explanations.  My
> new function is:
> 
> ;; exercise 2
> (defun union-helper (a b c)
>   (if (and (null a) (null b))
>       (reverse c)
>       (progn
>         (if (not (member (car a) c))
>             (setf c (cons (car a) c)))
>         (if (not (member (car b) c))
>             (setf c (cons (car b) c)))
>         (union-helper (cdr a) (cdr b) c))))
> 
> (defun my-union (a b)
>   (union-helper a b '()))
> 
> I return the reverse of c in order to have the elements in original
> order, as required by the exercise.  Related to this, but probably not
> worthy of starting a new thread, is the next exercise in Graham which
> I believed I successfully solved.  The task is to construct a
> function, occurences, which returns dotted lists of the element and
> the amount of times it repeats in a given list in order of most common
> to least, e.g. (occurences '(b c b)) => '((b . 2) (c . 1))
> 
> My implementations:
> 
> (defun occurences (lst)
>   (occurences-helper lst '()))
> 
> (defun occurences-helper (lst occur-lst)
>   (cond ((null lst) occur-lst)
>         ((if (member (first lst) (mapcar #'first occur-lst))
>              (let ((n (cdr (assoc (first lst) occur-lst))))
>                 (occurences-helper
>                 (cdr lst) (cons (cons (first lst) (+ 1 n))
>                                 (assoc-remove (first lst) occur-lst))))
>              (occurences-helper
>               (cdr lst) (cons (cons (first lst) 1) occur-lst))))))
> 
> (defun assoc-remove (item lst)
>   (if (null lst)
>       nil
>       (if (equal item (first (first lst)))
>           (assoc-remove item (cdr lst))
>           (cons (first lst) (assoc-remove item (cdr lst))))))
> 
> This works with my tests.  It returns the right results AFAIK.  I
> don't mean to waste your time with just looking over every answer I
> have to an exercise, but this code seems a bit excessive for what
> seems to be a simple exercise.  I repeatedly find myself coming up
> with solutions that may be clear in terms of the way the problem is
> approached, but include so many helper functions and long constructs
> that, considering this exercise only appears in ch. 4, I can't help
> but think I'm overlooking a much shorter and simpler solution.  Is
> that the case for this exercise?
> 
> Thanks again, I appreciate your help,
> --
> Jordan Katz <····@underlevel.net>  |  Mind the gap
From: David Sletten
Subject: Re: newbie question.
Date: 
Message-ID: <3C6F2175.6040905@home.com>
Jordan Katz wrote:

> Hello,
> 
>   I was in the process of learning Lisp (I'm using ANSI Common Lisp as
> my guide) but I stopped for a few months and now am trying to relearn
> it.  I was a beginner before, but now even the simple exercises from
> Graham's book puzzle me.  I tried solving the following exercises,
> from one of the early chapters, that asks to write a union function
> that maintains the order of lists.  I came up with the following
> "pseudo-code":
> 
>   1.  iterate through two lists, a and b.
>   2.  if both are null, return nil.
>   3.  store every element of a and b in a third list, c, unless:
>         - a is a member of c already
>         - or b is a member of c already
>   4.  take the cdr of a and cdr of b and continue.
> 
> My pseudo code, although probably horribly imperative and
> non-functional, seems correct to me.  I tried implementing it:
> 
> (defun union-helper (a b c)
>   (if (and (null a) (null b))
>       nil
>       (progn
>         (if (not (member (car a) c))
>             (setf c (cons (car a) c)))
>         (if (not (member (car b) c))
>             (setf c (cons (car b) c)))
>         (union-helper (cdr a) (cdr b) c))))
> 
> (defun union (a b)
>   (union-helper a b '()))
> 
> But it returns nil all the time.  It also seems to be, though I may be
> wrong, that such a simple function can really be written with out a
> helper.  Could someone point out to me what I did wrong in my
> function, and what the typical way (but still recursive because that's
> the method I'm really trying to learn as a beginner) to do it would
> be?  I appreciate all the help.
> 
> Thanks a lot,
> (P.S. I take no CS or Lisp related classes, this is for my own study.)
> 

The reason your function always returns NIL is because UNION-HELPER 
either returns NIL or the value of UNION-HELPER applied to the CDRs of A 
and B. This means that eventually A and B will eventually both be NIL, 
at which point the final call to UNION-HELPER returns NIL. All of the 
pending recursive calls just pass this back up the line to the original 
call. Instead, you should return C:
  (defun union-helper (a b c)
    (if (and (null a) (null b))
        c
        (progn
          (if (not (member (car a) c))
              (setf c (cons (car a) c)))
          (if (not (member (car b) c))
              (setf c (cons (car b) c)))
          (union-helper (cdr a) (cdr b) c))))

If A and B are NIL to begin with, so will C be NIL.

In any case, you should take a look at COND, which is more flexible than IF:
  (defun union-helper (a b c)
    (cond ((and (null a) (null b)) c)
          ((member (car a) c)
           (union-helper (cdr a) b c))
          ((member (car b) c)
           (union-helper a (cdr b) c))
          (t (union-helper (cdr a) (cdr b) (cons (car b)
                                                 (cons (car a) c)))) ))
But this is kind of a weird way to do it. Furthermore, since you are 
using C as an accumulator you wind up building the list backwards. So 
you'll have to reverse the final result to get things right:

   (defun union-helper (a b c)
    (cond ((and (null a) (null b)) (reverse c))
          ((member (car a) c)
           (union-helper (cdr a) b c))
          ((member (car b) c)
           (union-helper a (cdr b) c))
          (t (union-helper (cdr a) (cdr b) (cons (car b)
                                                 (cons (car a) c))))
You can simplify this by recognizing that both A and B are subsets of 
(union a b). Rather than starting with an empty set C, let C be either A 
or B. Then you can simply check items of the other set:
(defun union (a b)
   (cond ((null a) b)
         ((member (car a) b)
          (union (cdr a) b))
         (t (cons (car a) (union (cdr a) b)))) )

To satisfy the requirement that the elements remain in order (which is 
silly and meaningless if we are discussing sets):
(defun union (a b)
   (union-helper a b (reverse a)) )

(defun union-helper (a b result)
   (cond ((null b) (reverse result))
         ((member (car b) a)
          (union-helper a (cdr b) result))
         (t (union-helper a (cdr b) (cons (car b) result)))) )

For more discussion of Lisp, sets, and recursion take a look at:
http://68.48.48.43/sets/sets.html

David Sletten
From: Martti Halminen
Subject: Re: newbie question.
Date: 
Message-ID: <3C6FA3DA.48C70983@kolumbus.fi>
Jordan Katz wrote:

> I tried solving the following exercises,
> from one of the early chapters, that asks to write a union function
> that maintains the order of lists.  I came up with the following
> "pseudo-code":
> 
>   1.  iterate through two lists, a and b.
>   2.  if both are null, return nil.
>   3.  store every element of a and b in a third list, c, unless:
>         - a is a member of c already
>         - or b is a member of c already
>   4.  take the cdr of a and cdr of b and continue.
> 
> My pseudo code, although probably horribly imperative and
> non-functional, seems correct to me.  I tried implementing it:

Seems to me your pseudo-code isn't all that clear: in 1. you speak about
iterating through the list, in 3. you are doing something for every
element, and in 4 you are continuing, presumably recursively. That would
sum to going three times through the lists???


> (defun union-helper (a b c)
>   (if (and (null a) (null b))
>       nil
>       (progn
>         (if (not (member (car a) c))
>             (setf c (cons (car a) c)))
>         (if (not (member (car b) c))
>             (setf c (cons (car b) c)))
>         (union-helper (cdr a) (cdr b) c))))
> 
> (defun union (a b)
>   (union-helper a b '()))
> 
> But it returns nil all the time.  It also seems to be, though I may be
> wrong, that such a simple function can really be written with out a
> helper.  Could someone point out to me what I did wrong in my
> function, and what the typical way (but still recursive because that's
> the method I'm really trying to learn as a beginner) to do it would
> be?  I appreciate all the help.

Of course it returns nil, that's what you told it to do. Also, even if
you returned c, it would not preserve the order of the original list
items.

While it might be more effective to let you learn by trial and error,
here's a little more cleaned-out version:

(defun my-union2 (a b &optional (c nil))
  (if (and (null a)(null b))
      (nreverse c)
    (progn (pushnew (first a) c)
	   (pushnew (first b) c)
	   (my-union2 (rest a) (rest b) c))))

- This is slightly dangerous: if you ever do the top-level call with a
non-nil c, this will clobber its value for other users. It would be a
little safer with reverese instead of nreverse; wastes a little space,
though.

--
From: vsync
Subject: Re: newbie question.
Date: 
Message-ID: <87u1sfjo2y.fsf@prion.quadium.net>
Jordan Katz <····@underlevel.net> writes:

> (P.S. I take no CS or Lisp related classes, this is for my own study.)

Well, congratulations on your desire to learn.

And would that everyone else needing homework help asked as nicely as
you do...

-- 
vsync
http://quadium.net/
(cons (cons (car (cons 'c 'r)) (cdr (cons 'a 'o))) ; Orjner
      (cons (cons (car (cons 'n 'c)) (cdr (cons nil 's))) nil))
From: Kenny Tilton
Subject: Re: newbie question.
Date: 
Message-ID: <3C71465B.4E22538A@nyc.rr.com>
vsync wrote:
> And would that everyone else needing homework help asked as nicely as
> you do...

Cynic. Besides, a convincing-attempt-before-seeking-cll-help was
offered, and that's the price of admission.

-- 

 kenny tilton
 clinisys, inc
 ---------------------------------------------------------------
 "We have a pond and a pool. The pond would be good for you."
                                            - Ty to Carl, Caddy Shack
From: Jordan Katz
Subject: Re: newbie question.
Date: 
Message-ID: <m3lmdqtnkv.fsf@underlevel.underlevel.net>
Kenny Tilton <·······@nyc.rr.com> writes:

> vsync wrote:
> > And would that everyone else needing homework help asked as nicely as
> > you do...
> 
> Cynic. Besides, a convincing-attempt-before-seeking-cll-help was
> offered, and that's the price of admission.

I would also assume no CS teachers assign exercises directly from
Graham.
-- 
Jordan Katz <····@underlevel.net>  |  Mind the gap
From: vsync
Subject: Re: newbie question.
Date: 
Message-ID: <87pu32jpql.fsf@prion.quadium.net>
Jordan Katz <····@underlevel.net> writes:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> > vsync wrote:
> > > And would that everyone else needing homework help asked as nicely as
> > > you do...
> > 
> > Cynic. Besides, a convincing-attempt-before-seeking-cll-help was
> > offered, and that's the price of admission.
> 
> I would also assume no CS teachers assign exercises directly from
> Graham.

Hmm, I think you all misunderstand.  I was dead serious.  That request
for help was exactly as I would like to see all such requests,
assigned by an instructor or not.

-- 
vsync
http://quadium.net/
(cons (cons (car (cons 'c 'r)) (cdr (cons 'a 'o))) ; Orjner
      (cons (cons (car (cons 'n 'c)) (cdr (cons nil 's))) nil))
From: Daniel Barlow
Subject: Re: newbie question.
Date: 
Message-ID: <87n0y5xhb4.fsf@noetbook.telent.net>
vsync <·····@quadium.net> writes:

> > > > And would that everyone else needing homework help asked as nicely as
> > > > you do...

> Hmm, I think you all misunderstand.  I was dead serious.  That request
> for help was exactly as I would like to see all such requests,
> assigned by an instructor or not.

In which case I think your message would have been clearer if you had
omitted the word "else" from the original remark.


-dan

-- 

  http://ww.telent.net/cliki/ - Link farm for free CL-on-Unix resources 
From: Kenny Tilton
Subject: Re: newbie question.
Date: 
Message-ID: <3C730F8B.33D11030@nyc.rr.com>
Daniel Barlow wrote:
> 
> vsync <·····@quadium.net> writes:
> 
> > > > > And would that everyone else needing homework help asked as nicely as
> > > > > you do...
> 
> > Hmm, I think you all misunderstand.  I was dead serious.  That request
> > for help was exactly as I would like to see all such requests,
> > assigned by an instructor or not.
> 
> In which case I think your message would have been clearer if you had
> omitted the word "else" from the original remark.
> 

That would work. Me, I vote for striking "homework". :)

 kenny tilton
 clinisys, inc
 ---------------------------------------------------------------
 "We have a pond and a pool. The pond would be good for you."
                                            - Ty to Carl, Caddy Shack
From: vsync
Subject: Re: newbie question.
Date: 
Message-ID: <87k7t8ij3v.fsf@prion.quadium.net>
Kenny Tilton <·······@nyc.rr.com> writes:

> That would work. Me, I vote for striking "homework". :)

Hey, it can still be homework if you assign it to yourself...

-- 
vsync
http://quadium.net/
(cons (cons (car (cons 'c 'r)) (cdr (cons 'a 'o))) ; Orjner
      (cons (cons (car (cons 'n 'c)) (cdr (cons nil 's))) nil))
From: Tim Bradshaw
Subject: Re: newbie question.
Date: 
Message-ID: <ey3pu32z1tz.fsf@cley.com>
* Jordan Katz wrote:

> I would also assume no CS teachers assign exercises directly from
> Graham.

I suspect they do...
From: Kaz Kylheku
Subject: Re: newbie question.
Date: 
Message-ID: <ryYb8.56252$A44.3140219@news2.calgary.shaw.ca>
In article <··············@underlevel.underlevel.net>, Jordan Katz wrote:
>My pseudo code, although probably horribly imperative and
>non-functional, seems correct to me.  I tried implementing it:
>
>(defun union-helper (a b c)
>  (if (and (null a) (null b))
>      nil
>      (progn
>        (if (not (member (car a) c))
>            (setf c (cons (car a) c)))
>        (if (not (member (car b) c))
>            (setf c (cons (car b) c)))
>        (union-helper (cdr a) (cdr b) c))))

The adjoin function could help you here. It adds something to a list
unless it is already in that list, and returns a new list.

	(adjoin 1 '(1 2 3))  => (1 2 3)
	(adjoin 4 '(1 2 3))  => (4 1 2 3)
	(adjoin "foo" '("foo" bar") :test #'string=)  => ("foo" "bar")

>(defun union (a b)
>  (union-helper a b '()))

Since  Common Lisp already has a function called union already, the
behavior is undefined if you write your own.

Note that CL has many functions that operate on sequences,
which includes vectors and lists. Most of them take a :test argument
so you can specify how items are compared (the default test
is #'eql). Another useful parameter is :key, which specifies what
part of each element is to be tested. For example:

	;; find sublist whose second element is "three".

	(find 3 '((1 "two") (3 "four") (4 "three")) :key #'second 
	                                            :test #'string-equal)

>Thanks a lot,
>(P.S. I take no CS or Lisp related classes, this is for my own study.)
>-- 
>Jordan Katz <····@underlevel.net>  |  Mind the gap

The first thing you should study is what is already there, so you don't
have to waste your time on pointless exercises. Leave the reinvention
of basic functions to students of Scheme.
From: Kenny Tilton
Subject: Re: newbie question.
Date: 
Message-ID: <3C7144E7.3271298D@nyc.rr.com>
Kaz Kylheku wrote:
> The first thing you should study is what is already there, so you don't
> have to waste your time on pointless exercises. Leave the reinvention
> of basic functions to students of Scheme.

Coming from a roll-your-own world like "C" (stdlib aside), I re-invented
a lot of built-in CL wheels before realizing that when I needed
something there was a good chance it was already part of the language.

It's fun going back over my own newbie code in any newbie language
(Prolog takes the cake) and howling at the stuff I find there in re
doing stuff the language would have done for me. You can almost see the
learning curve.

-- 

 kenny tilton
 clinisys, inc
 ---------------------------------------------------------------
 "We have a pond and a pool. The pond would be good for you."
                                            - Ty to Carl, Caddy Shack
From: Thomas F. Burdick
Subject: Re: newbie question.
Date: 
Message-ID: <xcvr8nifsfq.fsf@apocalypse.OCF.Berkeley.EDU>
Kenny Tilton <·······@nyc.rr.com> writes:

> Kaz Kylheku wrote:
> > The first thing you should study is what is already there, so you don't
> > have to waste your time on pointless exercises. Leave the reinvention
> > of basic functions to students of Scheme.
> 
> Coming from a roll-your-own world like "C" (stdlib aside), I re-invented
> a lot of built-in CL wheels before realizing that when I needed
> something there was a good chance it was already part of the language.

For students, I think it's a good thing to implement these things.
Not students of a language, of course, but students of programming.
You learn how things work better, and then you really appreciate the
prefab versions that come with CL -- eg, I never realized how much I
love prefab hi-fi equipment until I built some of my own.

> It's fun going back over my own newbie code in any newbie language
> (Prolog takes the cake) and howling at the stuff I find there in re
> doing stuff the language would have done for me. You can almost see the
> learning curve.

I'm really enjoying looking over my first attempts at Smalltalk -- I
don't remember intending this at the time, but it kind of looks like I
was trying to port half of CL to Squeak :)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kaz Kylheku
Subject: Re: newbie question.
Date: 
Message-ID: <PTYb8.56308$A44.3146790@news2.calgary.shaw.ca>
In article <··············@underlevel.underlevel.net>, Jordan Katz wrote:
>My pseudo code, although probably horribly imperative and
>non-functional, seems correct to me.  I tried implementing it:
>
>(defun union-helper (a b c)
>  (if (and (null a) (null b))
>      nil
>      (progn
>        (if (not (member (car a) c))
>            (setf c (cons (car a) c)))
>        (if (not (member (car b) c))
>            (setf c (cons (car b) c)))
>        (union-helper (cdr a) (cdr b) c))))

The adjoin function could help you here. It adds something to a list
unless it is already in that list, and returns a new list.

	(adjoin 1 '(1 2 3))  => (1 2 3)
	(adjoin 4 '(1 2 3))  => (4 1 2 3)
	(adjoin "foo" '("foo" bar") :test #'string=)  => ("foo" "bar")

>(defun union (a b)
>  (union-helper a b '()))

Since  Common Lisp already has a function called union already, the
behavior is undefined if you write your own.

Note that CL has many functions that operate on sequences,
which includes vectors and lists. Most of them take a :test argument
so you can specify how items are compared (the default test
is #'eql). Another useful parameter is :key, which specifies what
part of each element is to be tested. For example:

	;; find sublist whose second element is "three".

	(find "three" '((1 "two") (3 "four") (4 "three")) 
              :key #'second :test #'string-equal)

>Thanks a lot,
>(P.S. I take no CS or Lisp related classes, this is for my own study.)
>-- 
>Jordan Katz <····@underlevel.net>  |  Mind the gap

The first thing you should study is what is already there, so you don't
have to waste your time on pointless exercises. Leave the reinvention
of basic functions to students of Scheme.


-- 
Meta-CVS: version control with directory structure versioning over top of CVS.
http://users.footprints.net/~kaz/mcvs.html