From: Sylvain
Subject: strings and function names
Date: 
Message-ID: <isidnSSbdouCoOzeRVn-pQ@speakeasy.net>
As an incentive to teach myself Lisp,  I am toying with dynamic
web pages generated with lisp (using the very helpful site
http://lisp.t2100cdt.kippona.net/lispy/home as a starting point);

now, I want of course to tweak and do things differently :-) for
instance,  I thought I could use a hash table to invoke the
correct function depending on the URL requested something like
that:

(defvar *dispatch-table* (make-hash-table :test #'equal))
(setf (gethash "/lisp/test" *dispatch-table) #'test-page)
(setf (gethash "/lisp/home" *dispatch-table) #'home-page)

...
;; command is the alist with the environment variables from mod_lisp
(defun dispatch (command)
   (let ((func (gethash (cdr (assoc "url command :test #'string=)) 
*dispatch-table*)))
     (if (null func) (home-page) (funcall func))))

ok, I am still a bit confused with proper use of eq vs eql vs equal,
working on it :-) -- and a hash table is an overkill for so few
URL to choose from,  but I'd like to scale the thing eventually;

what bothers me are all these (setf ...) lines to populate the
hashtable;  looks ugly and repetitive;  especially considering that
I name the function like the URL and vice versa;  i.e.,  I was
hoping to be able to declare list of URLs like this
(defconstant +urls+ (list "/lisp/test" "/lisp/home"))

and via a clever use of mapcar, populate the hashtable; but how
do I get a function name from a string or vice versa? (probably
wrong way to ask the question,  I hope someone understands nonetheless
what I mean) :-)

--Sylvain

From: William Bland
Subject: Re: strings and function names
Date: 
Message-ID: <pan.2005.11.09.00.31.15.549674@gmail.com>
On Tue, 08 Nov 2005 16:05:04 -0800, Sylvain wrote:

> what bothers me are all these (setf ...) lines to populate the
> hashtable;  looks ugly and repetitive;  especially considering that
> I name the function like the URL and vice versa;  i.e.,  I was
> hoping to be able to declare list of URLs like this
> (defconstant +urls+ (list "/lisp/test" "/lisp/home"))
> 
> and via a clever use of mapcar, populate the hashtable...

Personally I'd skip this as a potential solution (although it's not hard
to implement - see INTERN and FUNCTION in the hyperspec).  It requires you
to maintain the consistency of a mapping of the form "/lisp/name" ->
#'name-page, by hand. If you want to change the name of a page, you have
to touch multiple pieces of code.

Consider instead writing a macro, so that you can write something like

(def-web-handler ("/lisp/test")
	...code...)

and have it expand to

(setf (gethash "/lisp/test" *dispatch-table* (lambda () ...code...)))

You might find that easier to maintain since there is now no mapping that
you need to keep consistent.

Best wishes,
	Bill.
From: Sylvain
Subject: Re: strings and function names
Date: 
Message-ID: <wIWdnahxbYtowezenZ2dnUVZ_sudnZ2d@speakeasy.net>
William Bland wrote:
> 
> Consider instead writing a macro, so that you can write something like
> 
> (def-web-handler ("/lisp/test")
> 	...code...)
> 
> and have it expand to
> 
> (setf (gethash "/lisp/test" *dispatch-table* (lambda () ...code...)))


looks a lot better than the idea I had,  thanks!

--Sylvain
From: Barry Margolin
Subject: Re: strings and function names
Date: 
Message-ID: <barmar-F40504.20585508112005@comcast.dca.giganews.com>
In article <······························@gmail.com>,
 William Bland <···············@gmail.com> wrote:

> On Tue, 08 Nov 2005 16:05:04 -0800, Sylvain wrote:
> 
> > what bothers me are all these (setf ...) lines to populate the
> > hashtable;  looks ugly and repetitive;  especially considering that
> > I name the function like the URL and vice versa;  i.e.,  I was
> > hoping to be able to declare list of URLs like this
> > (defconstant +urls+ (list "/lisp/test" "/lisp/home"))
> > 
> > and via a clever use of mapcar, populate the hashtable...
> 
> Personally I'd skip this as a potential solution (although it's not hard
> to implement - see INTERN and FUNCTION in the hyperspec).  It requires you
> to maintain the consistency of a mapping of the form "/lisp/name" ->
> #'name-page, by hand. If you want to change the name of a page, you have
> to touch multiple pieces of code.
> 
> Consider instead writing a macro, so that you can write something like
> 
> (def-web-handler ("/lisp/test")
> 	...code...)
> 
> and have it expand to
> 
> (setf (gethash "/lisp/test" *dispatch-table* (lambda () ...code...)))
> 
> You might find that easier to maintain since there is now no mapping that
> you need to keep consistent.

I agree that this is the nicest way to do it.  But as a simple way to do 
it with the existing code, consider a simple loop:

(loop for (path func) in '(("/lisp/test" test-page)
                           ("/lisp/home" home-page)
                           ...)
  do (setf (gethash path *dispatch-table*) func))

Note also that I put the function name in the hash table, not the 
function object.  This way, if you redefine the function you don't have 
to update the dispatch table entry.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Sylvain
Subject: Re: strings and function names
Date: 
Message-ID: <wIWdnatxbYvWwOzenZ2dnUVZ_sudnZ2d@speakeasy.net>
Barry Margolin wrote:
> Note also that I put the function name in the hash table, not the 
> function object.  This way, if you redefine the function you don't have 
> to update the dispatch table entry.

ah! another thing I didn't think about,  thanks!

--Sylvain
From: Thomas A. Russ
Subject: Re: strings and function names
Date: 
Message-ID: <ymimzkdr9zr.fsf@sevak.isi.edu>
Sylvain <····@att.net> writes:

> 
> As an incentive to teach myself Lisp,  I am toying with dynamic
> web pages generated with lisp (using the very helpful site
> http://lisp.t2100cdt.kippona.net/lispy/home as a starting point);
> 
> now, I want of course to tweak and do things differently :-) for
> instance,  I thought I could use a hash table to invoke the
> correct function depending on the URL requested something like
> that:
> 
> (defvar *dispatch-table* (make-hash-table :test #'equal))
> (setf (gethash "/lisp/test" *dispatch-table) #'test-page)
> (setf (gethash "/lisp/home" *dispatch-table) #'home-page)

Of course, another solution entirely is to use the URL itself as the
function name.  This is not quite as flexible, since you lose the
ability to easily map multiple URLs to the same handler function, but it
provides a fairly simple dispatch mechanism:

(defun |/lisp/test| (stream) ...)
(defun |/lisp/home| (stream) ...)

presuming that you want to have the handler output something to a
particular stream in order to generate the page.

> ;; command is the alist with the environment variables from mod_lisp
> (defun dispatch (command)
>    (let ((func (gethash (cdr (assoc "url command :test #'string=)) 
> *dispatch-table*)))
>      (if (null func) (home-page) (funcall func))))

(defun dispatch (command stream)
  (let* ((url (cdr (assoc "url" command :test #'string=)))
         (function-name (when url (intern url *my-package*))))
     (funcall function-name stream)))



-- 
Thomas A. Russ,  USC/Information Sciences Institute