Hi,
I'm using cl-who for a project where I want to generate 2 kinds of XML, and each has their own prologue. I started by passing these as literals to the keyword parameter :prologue, but I'd like to pull them out into constants, and eventually one will need to be computed at runtime.
At first, I tried just passing an expression to :prologue, but that obviously failed (because defmacro evaluates it at macroexpand-time, not run-time, I think):
(defconstant +my-prologue+ "header") (with-html-output-to-string (s nil :prologue +my-prologue+) (:a)) => " <a></a>"
Then I went and read Erann Gat's "Idiot's Guide to Special Variables". It doesn't mention macros, but I figured I could get close with something like this, but no, it ignores my *prologue* setting:
(let ((*prologue* "header")) (with-html-output-to-string (s nil :prologue t) (:a))) => "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> <a></a>"
So obviously I'm missing the boat on special variables and defmacro. I know I could just setq *prologue* before calling cl-who (or even cruder approaches), but that seems awkward, and I'd like to learn what's going on with special variables and macros.
As an aside, special variables and macros aren't behaving the same in my 2 Lisp implementations (all of the above is with SBCL), so it seems that at least somebody out there thinks the same way as me: :-)
(defvar *special* 5) (defun show-special () *special*) (defmacro with-special () *special*) (show-special) (let ((*special* 10)) (show-special)) (with-special) (let ((*special* 10)) (with-special))
;; CLISP 2.43: 5, 10, 5, 10 ;; SBCL 1.0.13: 5, 10, 5, 5
If anybody could shed some light on this, and show how to most naturally use an expression as a :prologue with cl-who, it'd be much appreciated.
Thanks!
- Ken
Dear Ken,
So obviously I'm missing the boat on special variables and defmacro. I know I could just setq *prologue* before calling cl-who (or even cruder approaches), but that seems awkward,
Awkward indeed! But if you put it into a well-separated function it's not that bad.
and I'd like to learn what's going on with special variables and macros.
Yes, that's important.
As an aside, special variables and macros aren't behaving the same in my 2 Lisp implementations (all of the above is with SBCL), so it seems that at least somebody out there thinks the same way as me: :-)
(defvar *special* 5) (defun show-special () *special*) (defmacro with-special () *special*) (show-special) (let ((*special* 10)) (show-special)) (with-special) (let ((*special* 10)) (with-special))
;; CLISP 2.43: 5, 10, 5, 10 ;; SBCL 1.0.13: 5, 10, 5, 5
Don't take my word for it, but my guess is that you've fallen right into the compiler/interpreter trap.
SBCL is a compiler-only implementation and CLISP interprets code by default.
I'll leave it as an exercise to you what exactly happens here.
If anybody could shed some light on this, and show how to most naturally use an expression as a :prologue with cl-who, it'd be much appreciated.
Not sure here either but take a look at the macro:
(defmacro with-html-output ((var &optional stream &key prologue ((:indent *indent*) *indent*)) &body body) (when (and *indent* (not (integerp *indent*))) (setq *indent* 0)) (when (eq prologue t) (setq prologue *prologue*)) `(let ((,var ,(or stream var))) ,(tree-to-commands body var prologue)))
*prologue* gets evaluated at macro expansion time, and I suppose special bindings are not in effect then. Wild guess. Wade through the spec to find out.
Or maybe someone else can point it out.
The solution here is using macros to define your own prologues.
Thanks!
Thanks for checking out Common Lisp!
Leslie
Hi Leslie,
Thanks for responding!
I think I'm still in detox from a long Ruby project. :-) I think I was thinking that part of the macroexpansion would occur at runtime or something. I'm now trying to use it more as it seems to have been intended to be used.
The solution here is using macros to define your own prologues.
Maybe, but for now, I'm just prepending my own prologue outside of the (with-html-output...) call. I want to get something working fast, and there are more interesting parts of the problem to attack.
- Ken