From: Joe Foran
Subject: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <44bd5fab$0$19617$88260bb3@free.teranews.com>
Hi,

I'm currently trying to teach myself Lisp and am working my way through 
Paul Graham's book. One of the exercises for chapter 4 asks the reader 
to define a function that takes a hash table and returns a corresponding 
assoc-list.

My attempt at an answer is as follows

(defun assoc-from-hash (ht)
   (let ((assocList nil))
     (maphash #'(lambda (k v)
                  (append assocList (list (cons k v)))) ht )
     assocList))

I created a hash table as follows

(setf ht (make-hash-table))
(setf (gethash 'animal ht) 'dog)
(setf (gethash 'vegetable ht) 'carrot)
(setf (gethash 'mineral ht) 'zinc)

and when I call the function
(assoc-from-hash ht)
Lisp evaluates this as nil

What I'm trying to get is a list of the form
((ANIMAL . DOG) (VEGETABLE . CARROT) (MINERAL . ZINC))
but I can't get it to work.

The reason's probably something very simple but I can't see it. Can 
anyone point out where I'm going wrong?

In case it's pertinent, I'm using CLISP 2.38 with SLIME on Windows XP.

Thanks,
Joe

-- 
Posted via a free Usenet account from http://www.teranews.com

From: Eric Hanchrow
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <87vepu5v2u.fsf@offby1.atm01.sea.blarg.net>
You're misusing "append", in typical newbie fashion :-)

Try this:

       (defun assoc-from-hash (ht)
           (let ((assocList nil))
             (maphash #'(lambda (k v)
                          (setf assocList (append assocList (list (cons k v))))) ht )
             assocList))

The only difference is that I'm calling "setf" on the result of "append".
-- 
I shrivel inside each time [Star Wars] is mentioned.
        -- Sir Alec Guinness
From: Joe Foran
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <44bd69c7$0$19643$88260bb3@free.teranews.com>
Eric Hanchrow wrote:
> You're misusing "append", in typical newbie fashion :-)
> 
> Try this:
> 
>        (defun assoc-from-hash (ht)
>            (let ((assocList nil))
>              (maphash #'(lambda (k v)
>                           (setf assocList (append assocList (list (cons k v))))) ht )
>              assocList))
> 
> The only difference is that I'm calling "setf" on the result of "append".

Yeah, that works. Seems so obvious now :-)

Thanks,
Joe

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Sacha
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <C8hvg.544829$HO7.13105182@phobos.telenet-ops.be>
"Joe Foran" <········@gmail.com> wrote in message 
······························@free.teranews.com...
> Eric Hanchrow wrote:
>> You're misusing "append", in typical newbie fashion :-)
>>
>> Try this:
>>
>>        (defun assoc-from-hash (ht)
>>            (let ((assocList nil))
>>              (maphash #'(lambda (k v)
>>                           (setf assocList (append assocList (list (cons k 
>> v))))) ht )
>>              assocList))
>>
>> The only difference is that I'm calling "setf" on the result of "append".
>

This algorithm will have very bad performances for a big hash-table as the 
append function will need to run down the association list on each 
iteration.  I would use the loop facility, collecting the conses, or even 
better just push the cons on the list as the order is not important (coming 
from a hash-table anyways).

Sacha 
From: Rob Warnock
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <ntudnbd-cutoYiDZnZ2dnUVZ_qidnZ2d@speakeasy.net>
Sacha <··@address.spam> wrote:
+---------------
| "Joe Foran" <········@gmail.com> wrote in message 
| > Eric Hanchrow wrote:
| >> You're misusing "append", in typical newbie fashion :-)
| >> Try this:
...
| >> The only difference is that I'm calling "setf" on the result of "append".
| 
| This algorithm will have very bad performances for a big hash-table as the 
| append function will need to run down the association list on each 
| iteration.  I would use the loop facility, collecting the conses, or even 
| better just push the cons on the list as the order is not important (coming 
| from a hash-table anyways).
+---------------

Indeed. Here's my own personal convenience function for this:

    (defun hash-table-alist (table &key (test (constantly t)))
      (let (result)
	(do-hash (key value table result)
	  (when (funcall test key value)
	    (push (cons key value) result)))))

In OP's case, he might not need the generality of the :TEST keyword, so:

    (defun hash-table-alist (table)
      (let (result)
	(do-hash (key value table result)
	  (push (cons key value) result))))

One can also do it with LOOP [albeit with a somewhat awkward syntax]
this way:

    (defun hash-table-alist (table)
      (loop for key being the hash-keys in table
		using (hash-value value)
	collect (cons key value)))


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Bill Atkins
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <1153322429.578828.128820@m73g2000cwd.googlegroups.com>
Rob Warnock wrote:
> Sacha <··@address.spam> wrote:
> +---------------
> | "Joe Foran" <········@gmail.com> wrote in message
> | > Eric Hanchrow wrote:
> | >> You're misusing "append", in typical newbie fashion :-)
> | >> Try this:
> ...
> | >> The only difference is that I'm calling "setf" on the result of "append".
> |
> | This algorithm will have very bad performances for a big hash-table as the
> | append function will need to run down the association list on each
> | iteration.  I would use the loop facility, collecting the conses, or even
> | better just push the cons on the list as the order is not important (coming
> | from a hash-table anyways).
> +---------------
>
> Indeed. Here's my own personal convenience function for this:
>
>     (defun hash-table-alist (table &key (test (constantly t)))
>       (let (result)
> 	(do-hash (key value table result)
> 	  (when (funcall test key value)
> 	    (push (cons key value) result)))))
>
> In OP's case, he might not need the generality of the :TEST keyword, so:
>
>     (defun hash-table-alist (table)
>       (let (result)
> 	(do-hash (key value table result)
> 	  (push (cons key value) result))))
>

What is DO-HASH?

(defun hash-table-to-alist (table)
  (let (result)
    (maphash (lambda (k v) (push (cons k v) result))
                   table)
    result))
From: Rob Warnock
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <7rednZnHIqBN0iLZnZ2dnUVZ_o2dnZ2d@speakeasy.net>
Bill Atkins <·········@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > (defun hash-table-alist (table)
| >   (let (result)
| > 	(do-hash (key value table result)
| > 	  (push (cons key value) result))))
| 
| What is DO-HASH?
+---------------

Oops!! My bad. Sorry for not spotting that earlier.
It seems that DO-HASH is a CMUCL extension:

    cmu> (describe 'do-hash)
    DO-HASH is an external symbol in the EXTENSIONS package.
    Macro-function: #<Byte function (:MACRO DO-HASH) {28F9EEE9}>
    Macro documentation:
      DO-HASH (Key-Var Value-Var Table [Result]) Declaration* Form*
       Iterate over the entries in a hash-table.
    ...

that expands into a call of WITH-HASH-TABLE-ITERATOR, very
similar to the example definition of MAP-HASH in the CLHS
entry for WITH-HASH-TABLE-ITERATOR, except that instead of
FUNCALL'ing a function it executes a &BODY.

+---------------
| (defun hash-table-to-alist (table)
|   (let (result)
|     (maphash (lambda (k v) (push (cons k v) result))
|              table)
|     result))
+---------------

Yes, that's an equivalent standard-conformant way to define it.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: William James
Subject: Re: Excerise in Graham's ANSI Common Lisp
Date: 
Message-ID: <1153420550.011901.265350@s13g2000cwa.googlegroups.com>
Joe Foran wrote:
> Hi,
>
> I'm currently trying to teach myself Lisp and am working my way through
> Paul Graham's book. One of the exercises for chapter 4 asks the reader
> to define a function that takes a hash table and returns a corresponding
> assoc-list.
>
> My attempt at an answer is as follows
>
> (defun assoc-from-hash (ht)
>    (let ((assocList nil))
>      (maphash #'(lambda (k v)
>                   (append assocList (list (cons k v)))) ht )
>      assocList))
>
> I created a hash table as follows
>
> (setf ht (make-hash-table))
> (setf (gethash 'animal ht) 'dog)
> (setf (gethash 'vegetable ht) 'carrot)
> (setf (gethash 'mineral ht) 'zinc)
>
> and when I call the function
> (assoc-from-hash ht)
> Lisp evaluates this as nil
>
> What I'm trying to get is a list of the form
> ((ANIMAL . DOG) (VEGETABLE . CARROT) (MINERAL . ZINC))
> but I can't get it to work.

In MatzLisp or Ruby:

h = { :animal, :dog,   :vegetable, :carrot,   :mineral, :zinc }
h.to_a