From: Christophe Rhodes
Subject: conditions and cgi-bin hackery
Date: 
Message-ID: <sqpup2wzkb.fsf@lambda.jesus.cam.ac.uk>
I was thinking this evening of writing a web front-end to a database
(of sheet-music, as it happens, but I don't think that's relevant). I
know that there are any number of cgi libraries for lisp that I could
use, but since this is part of the learning process, I thought I'd
think about it myself, and I came up with what I thought was something
fairly interesting.

In quite a lot of these things, you get something like

[ UNTESTED CODE ]

(defmacro deftag (tag-name)
  `(defun ,tag-name (properties &rest contents)
     (format nil "<~a ~:{~a=\"~a\"~^ ~}>~{~a~^ ~}</~a>" 
             ',tag-name properties contents ',tag-name)))

(deftag a)
(deftag title)

[...]

But this seems tedious, and not very interesting. I've been there,
several years ago (in scheme). Anyway, something semi-clicked about
conditions, and I thought, well, why not do something like this:

(handler-bind
    ((undefined-function 
      #'(lambda (c)
          (let ((tag-name (cell-error-name c)))
            (setf (symbol-function tag-name)
                  #'(lambda (properties &rest contents))
                      (format nil ...))))
 (format t (html nil (head nil (title nil "My title") ...))))))

Which of course works, up to a point, in that it can set the first
undefined function it comes across, but it doesn't restart from there.

This thought led me to the restart-case thing, but at that point my
brain gave up. Has someone done this already? Can someone point me to
something to read that might give me a clue as to how to restart the
computation from where we used the undefined function, but with the
new value of the function (this should be possible, right?)

Many thanks,

Christophe

From: David Bakhash
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <c291z1ijsmx.fsf@nerd-xing.mit.edu>
Christophe Rhodes <·····@cam.ac.uk> writes:

> This thought led me to the restart-case thing, but at that point my
> brain gave up. Has someone done this already? Can someone point me to
> something to read that might give me a clue as to how to restart the
> computation from where we used the undefined function, but with the
> new value of the function (this should be possible, right?)

while this is a neat way to go about it, my opinion is that it's _not_
the way to do it right, and (imo) misuse of the condition system.  I
think that the system you want to look at is The `HTML' macro used in
AllegroServe, which you can read about it at

http://allegroserve.sourceforge.net

I think that they did it right.  here's a code sample from their
tutorial, taken out of context (of a computed URL):

(html
 (:html
  (:head (:title "Hello Counter"))
  (:body 
   ((:font :color (nth (random 5)
		       '("red" "blue" 
			 "green" "purple" 
			 "black")))
    "Hello World had been called " 
    (:princ (incf count)) 
    " times"))))

If what you're looking for is a neat hack, and an interesting thing you
can do with conditions, then go for it.

the HTML macro, as it is, can have default behavior for apparent
keyword funcalls (e.g. (:font ...)).  That behavior is similar, if not
identical, to your DEFTAG macro.  But since it all occurs lexically
inside the HTML macro, it's all very nice and simple.  The key is to
keep it simple, and conditions are not as simple as this.  

dave
From: Christophe Rhodes
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <sqvgys7er6.fsf@lambda.jesus.cam.ac.uk>
David Bakhash <·····@alum.mit.edu> writes:

> Christophe Rhodes <·····@cam.ac.uk> writes:
>
> > This thought led me to the restart-case thing, but at that point my
> > brain gave up. Has someone done this already? Can someone point me to
> > something to read that might give me a clue as to how to restart the
> > computation from where we used the undefined function, but with the
> > new value of the function (this should be possible, right?)
> 
> while this is a neat way to go about it, my opinion is that it's _not_
> the way to do it right, and (imo) misuse of the condition system.  I
> think that the system you want to look at is The `HTML' macro used in
> AllegroServe, which you can read about it at
> 
> http://allegroserve.sourceforge.net
> 
> I think that they did it right.  here's a code sample from their
> tutorial, taken out of context (of a computed URL):
> 
> (html
>  (:html
>   (:head (:title "Hello Counter"))
>   (:body 
>    ((:font :color (nth (random 5)
> 		       '("red" "blue" 
> 			 "green" "purple" 
> 			 "black")))
>     "Hello World had been called " 
>     (:princ (incf count)) 
>     " times"))))

Yes. However, what happens when the HTML (or XHTML or whatever they
call it these days) standard is updated? Well, in one sense, nothing,
since the particular HTML version used is almost irrelevant in the
real world, where the browser is king, so let's consider XML instead;
quite possibly, a lisp application may need to generate XML, where we
don't know in advance what tags we'll need; at this point, this
condition hack might be more useful...

> If what you're looking for is a neat hack, and an interesting thing you
> can do with conditions, then go for it.

... though this is probably my main motivation. It appears that
neither clisp nor cmucl have the needed restart behaviour (my na�ve
first attempt at putting it in to cmucl caused my machine to crash,
sadly). Since acl seems to have it, I'll try that for the moment.

Christophe
From: Tim Bradshaw
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <ey3sntwzewz.fsf@cley.com>
* Christophe Rhodes wrote:
> Yes. However, what happens when the HTML (or XHTML or whatever they
> call it these days) standard is updated? Well, in one sense, nothing,
> since the particular HTML version used is almost irrelevant in the
> real world, where the browser is king, so let's consider XML instead;
> quite possibly, a lisp application may need to generate XML, where we
> don't know in advance what tags we'll need; at this point, this
> condition hack might be more useful...

Not at all.  an HTML generating macro doesn't need to know the names
of the tags.  Mine for one just assumes that any keyword is an HTML
tag.  The only thing it needs to know about is empty tags so it can
avoid generating <br></br>.  With XML you can know that from the name
(can't you?).  OTOH with XML you have a whole exciting new complexity
with things like namespaces and so on I think, but if you're dealing
with them you probably need to know the set of allowed tags anyway.

--tim
From: Christophe Rhodes
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <sqya3oo53i.fsf@lambda.jesus.cam.ac.uk>
Tim Bradshaw <···@cley.com> writes:

> * Christophe Rhodes wrote:
> > Yes. However, what happens when the HTML (or XHTML or whatever they
> > call it these days) standard is updated? Well, in one sense, nothing,
> > since the particular HTML version used is almost irrelevant in the
> > real world, where the browser is king, so let's consider XML instead;
> > quite possibly, a lisp application may need to generate XML, where we
> > don't know in advance what tags we'll need; at this point, this
> > condition hack might be more useful...
> 
> Not at all.  an HTML generating macro doesn't need to know the names
> of the tags.  

Indeed; I was referring to my understanding of the allegroserve
implementation, which defines LispHTML datastructures; only valid HTML
entities and certain special operators are allowed as the initial
keywords in the lists (see
http://allegroserve.sourceforge.net/htmlgen.html)

> Mine for one just assumes that any keyword is an HTML
> tag.  The only thing it needs to know about is empty tags so it can
> avoid generating <br></br>.  With XML you can know that from the name
> (can't you?).  OTOH with XML you have a whole exciting new complexity
> with things like namespaces and so on I think, but if you're dealing
> with them you probably need to know the set of allowed tags anyway.

I don't even pretend to understand XML's handling of namespaces; I've
not yet come across an application which uses XML namespaces,
either. XML deals with the empty tag problem (IIRC) by saying that
empty tags should be self-closing (<br />, for example) so in that
sense it's a lot nicer to use than HTML/SGML.

It's true that a more correct way of doing things might well be to
parse the XML DTD, and generate the relevant functions from that;
the conditions way, I should emphasize, is mainly motivated by my
efforts to understand the conditions system. As a sidenote, I believe
Perl's XML::Generator module does something along the lines of this
conditions hack...

Christophe
From: Pierre R. Mai
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <87k8f8xtuh.fsf@orion.dent.isdn.cs.tu-berlin.de>
Christophe Rhodes <·····@cam.ac.uk> writes:

> I don't even pretend to understand XML's handling of namespaces; I've
> not yet come across an application which uses XML namespaces,
> either. XML deals with the empty tag problem (IIRC) by saying that
> empty tags should be self-closing (<br />, for example) so in that
> sense it's a lot nicer to use than HTML/SGML.

Minor nit:  <br/> is exactly equivalent to <br></br> in both XML and
all SGML applications that support Annex K of ISO 8879 (which was
introduced by the TC 2 dated December 1997), a.k.a. WebSGML.  Most
seriously supported SGML applications track the standard, especially
w.r.t. XML interoperability, given it's marketing effectiveness...

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Steven M. Haflich
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <3959A554.7EDEC61F@pacbell.net>
There may be lots of different ways to do this in various
implementations, but the ANS-compliant way to do it would
be to FIND-RESTART for 'store-value, and failing that,
'use-value, then invoke that restart with your function.
See ANS 9.2.44 for example code that does something
similar.

The problem is that there is no apparent requirement that
an implementation actually provide either of these
restarts when an undefnied function is called.  If the
implementation doesn't, there is nothing portable you
can do to recover.  So you must
augment the 9.2.44 example with a test to see whether
a restart was actually found.

It is not possible in general to restart arbitrary
computations.  The ANS makes a firm guarantee that a call
to ERROR will never return.  It is only possible to
restart at contours where either the application code or
the implementation has explicitly provided for restarting
via RESTART-BIND or RESTART CASE.

ACL does provide the appropriate restart, and I suspect
other quality implementations do as well.

==========
"Is that a metacircularity in your pocket, or are you
just glad to see me?"  -- Mae West
From: Christophe Rhodes
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <squ2eco483.fsf@lambda.jesus.cam.ac.uk>
"Steven M. Haflich" <·······@pacbell.net> writes:

> ACL does provide the appropriate restart, and I suspect
> other quality implementations do as well.

ACL certainly does, and the following code works:

-- cut here --
(handler-bind
 ((undefined-function
   #'(lambda (c)
       (let ((symbol (cell-error-name c)))
	 (invoke-restart 'store-value
                   #'(lambda (&rest args)
                       (format nil
                               "<~a>~{~a~}</~a>"
                               (string symbol)
                               args
                               (string symbol))))))))
 (html (head (title "foo"))
       (body (p "This is a paragraph")
	     (p "So is this")
;	     (ul (map #'li '("This" "is" "a" "list")))
	     )))
-- cut here --

(where the value to store should actually be a little more
complicated, depending on how you want to represent your HTML as
lisp).

However, unfortunately, the commented line does not work in ACL (at
least, 5.0.1 Trial for Linux); the store-value restart does not appear
to be available for #'li errors.

Ah well -- at least I'm beginning to understand what's going on...

Christophe
From: Colin Walters
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <85u2e8541r.fsf@meta.verbum.org>
Christophe Rhodes <·····@cam.ac.uk> writes:

> I was thinking this evening of writing a web front-end to a database
> (of sheet-music, as it happens, but I don't think that's relevant). I
> know that there are any number of cgi libraries for lisp that I could
> use [...]

Could you give me some examples?  I am trying to find resources for
web programming with Common Lisp.  In particular, is there something
similar to LAML (http://www.cs.auc.dk/~normak/laml/), but for Common
Lisp?
From: Paolo Amoroso
Subject: Re: conditions and cgi-bin hackery
Date: 
Message-ID: <GJJgOWfJtF3g=9WWnCTM+yeHb8FR@4ax.com>
On 02 Jul 2000 22:41:04 -0400, Colin Walters <·······@cis.ohio-state.edu>
wrote:

> Could you give me some examples?  I am trying to find resources for
> web programming with Common Lisp.  In particular, is there something

You may check the Web section of Daniel Barlow's CLiki site:

  http://ww.telent.net/cliki/

If you find tools or resources not listed there, please add some info about
them: everybody has write access to CLiki.


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/