4 ms·
> a completely different semantic thanks to macros. Most of the time, you use functions. Sometimes, you need to define "WITH-X" macros or "DO-Y" iterators, or
by junke 10y ago
> a completely different semantic thanks to macros.
Most of the time, you use functions. Sometimes, you need to define "WITH-X" macros or "DO-Y" iterators, or a custom "DEFINE-Z" to shorten declarations (I tend to use macrolet for that).
(defun rgb (r g b) (format nil "#~@{~2,'0x~}" r g b))
(defparameter *background* (rgb 10 10 30))
(defparameter *foreground* (rgb 90 90 255))
(with-html-output-to-string (s)
(:html
(:head
(:title "Hello")
(:style :media "screen"
:type "text/css"
(str (cl-css:css
`((:body :background-color ,*background*
:color ,*foreground*)))))
(:script :type "text/javascript"
(str
(ps:ps
(setf (ps:@ window onload)
(lambda () (alert "Message")))))))
(:body
(:h1 "Heading"))))
The above is an example of what I consider a heavy usage of macros, and yet somehow I find it readable.
(the output is here: http://pastebin.com/raw/S5cb5ufC http://pastebin.com/raw/S5cb5ufC)
- junke 10y agoA little more interesting javascript code, in place of the above: (alert (list (ps:lisp *foreground*) (ps:lisp *background*)))
- SeanLuke 10y agoFor me the #1 rule for macros is to never, ever use one if you can use a function instead. With this in mind, surely you could just write (html (head (title "Hello") (style :media "screen" :type "text/css" ........)))) What is the value of a macro in this context?
- kiiski 10y agoI think the idea is that the macro expands into an efficient template. Instead of having to always build the same constant strings for every request, you can expand into a bunch of WRITE-STRINGs, with the dynamic parts in between.
- junke 10y agoThe macro is documented here: http://weitz.de/cl-who/#syntax http://weitz.de/cl-who/#syntax In particular, each list beginning with a keyword is transformed into an (X)HTML tag. It is an easy way to handle all current and future HTML elements without defining a function for each element and their attributes. You might be thinking: "we could generate invalid HTML", and yes, it is true. Other libraries exist to generate HTML, but this one is quite popular. The other interesting thing is that by processing the tree at compile time, you can make some optimizations. For example, the following form: (:html (:body (:h1 "Hi"))) ... is expanded as: (WRITE-STRING "<html><body><h1>Hi</h1></body></html>" *STANDARD-OUTPUT*) ... because it does not depend on external data. However, if instead of a constant string, you place (str (something)), you have instead: (WRITE-STRING "<html><body><h1>" *STANDARD-OUTPUT*) (LET ((CL-WHO::*INDENT* NIL)) NIL (STR (SOMETHING))) (WRITE-STRING "</h1></body></html>" *STANDARD-OUTPUT*)))