Thanks to everyone for the thoughtful comments! Some of the advanced
stuff went over my head. I'll have to do some studying :)
Personally I would be content with a portable macroexpand that simply
shows some Scheme syntax that's nice to view in the REPL so you can find
out whether the macro is expanding to the code you expect. Common Lisp
has a standard `macroexpand-1` for this purpose and it's supremely
convenient.
The precise naming of identifiers in the output due to hygiene,
environments and other concerns probably doesn't matter for this
purpose. And it doesn't matter whether the output can be evaluated in
the REPL; it's enough to be able to view it. After all, we can always
evaluate the macro by inputting it without the (macroexpand ...) around
it. The output cannot be the same in every Scheme that implements the
SRFI, and that's perfectly fine. It doesn't matter if things like `case`
expand to different primitive forms in different implementations, etc.
Even if hygiene things and lexical scoping are neglected in the output, one cannot neglect them for the input of such a hypothetical "macroexpand" or "macroexpand-1". So either "macroexpand" has to be a special form (that is able to capture the lexical context, in which to do the expansion) or the argument to "macroexpand" already has to be a syntax object that is enriched with lexical information.
In the former case, one would be able to call it as in: "(macroexpand (foo 1 2 3))". In the latter case, as in: "(macroexpand #'(foo 1 2 3))", where #' is a placeholder for an operation that syntactically closes a piece of program text over the current syntactic environment.
Marc
Of course if someone wants something more ambitious, I wouldn't stop them :)