Subject: Re: macro functionality in embedded languages.
From: rpw3@rpw3.org (Rob Warnock)
Date: Thu, 05 Apr 2007 22:19:21 -0500
Newsgroups: comp.lang.lisp
Message-ID: <w4mdnY9a6YqkIYjbnZ2dnUVZ_s-rnZ2d@speakeasy.net>
<hjstein@gmail.com> wrote:
+---------------
| It's not uncommon to see an embedded language in CL in macro style,
| as in:
|   (html:output (html:body ...))
| when one could instead use a function, as in:
|   (html:output '(html:body ...))
+---------------

But if the body is a constant, as you've shown here, how does
one insert dynamically-calculated HTML or even dynamically-
calculated plain text into the body?!? That is, how do you do
the equivalent of this in your "function" form [taken from
<http://rpw3.org/hacks/lisp/appsrv-demo.lhp>] ?

    (lhp-basic-page ()		; defaults to HTOUT-2.1 syntax
      (:html ()
       (:head () (:title () title))
       (lfd)
       (:body (:bgcolor "#ffffff") (lfd)
       ...[details elided]...

	 ;; Show the results, first a number and its powers in a row.
	 (:table () (lfd)
	   (:tr () (loop for e from 1 to pows and h in headings do 
		  (let ((p (cond ((= e 1) ":") ((= e pows) "") (t ","))))
		    (htm (:th (:nowrap) (fmt h e) p)))))
	   (loop for i from 1 to nums do
	     (htm (lfd) (:tr (:align "right")
	       (loop for e from 1 to pows do
		 (htm (:td () (princ (expt i e) lhp-stream))))))))

       ...[details elided]...)))

+---------------
| One advantage of the macro style is efficiency - the call expands at
| compile time and can be compiled with full optimization.  The macro
| can be written in such a way that it expands to reasonably efficient code.
+---------------

Another *major* advantage of what you're calling "the macro style" is
that one has full access to the full Common Lisp environment at both
macro-expansion time *and* run-time, and can easily interweave the
HTML-generating macros with other more-complex or more-general Common
Lisp code. [See my example above.]

In order to obtain the same flexibility from "the function style",
you'd need to make the arguments of the function be closures,
not constants, so you could do stuff like this [the above <TABLE>
example transliterated into a non-macro "function style"]:

    (html:table
      (lambda ()
	(html:tr
          (lambda ()
	    (loop for e from 1 to pows and h in headings do 
	      (let ((p (cond ((= e 1) ":") ((= e pows) "") (t ","))))
		(html:th
		  (lambda () (fmt h e) p)
		  :nowrap t)))))

	(loop for i from 1 to nums do
	  (html:lfd)
	  (html:tr
            (lambda ()
	      (loop for e from 1 to pows do
	        (html:td
                  (lambda () (princ (expt i e) lhp-stream)))))
	    :align "right"))))

Notice how this also forces the optional "attributes" of any
HTML element into being *after* the closure which generates
the content of the element. Ugly. Error-prone.

No, I'll stick with "the macro style", thanks...


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607