Re section 5.8, "Fresh syntax", in the syntax-case draft:
> Should we consider instead a variant of 'syntax', say 'fresh-syntax',
> that applies a unique mark to its output? Should we consider
> something more general, like MzScheme's 'make-syntax-introducer',
> which creates a procedure that applies the same mark to a syntax
> object each time it is applied? Either can be used to define
> 'generate-temporaries', which can then be considered a derived
> procedure.
I'm not sure that either of these approaches will address the issue all
that well. To illustrate, here's an example adapted from SRFI 72 and
modified to run under MzScheme, using MzScheme's
'syntax-local-introduce'. (It can also be written to use
'make-syntax-introducer', which doesn't make any difference for my
purposes.)
(define-syntax main
(lambda (stx)
(let ((make-swap
(lambda (x y)
(with-syntax ((x (syntax-local-introduce x))
(y (syntax-local-introduce y)))
(syntax-local-introduce
(syntax
(let ((t x))
(set! x y)
(set! y t))))))))
(syntax-case stx ()
((_)
(with-syntax ((swap (make-swap (syntax s) (syntax t))))
(syntax
(let ((s 1) (t 2))
swap
(list s t)))))))))
(main) ;=> (2 1)
This gives the expected result. If the uses of syntax-local-introduce
are removed, the result changes to (1 2), which is not what is intended.
To achieve the intended result, some ability to control the marks
introduced by make-swap is needed.
However, doing this using procedures like syntax-local-introduce or
make-syntax-introducer requires reasoning about mark introduction and
cancellation, which can be tedious even in trivial cases such as the above.
(Aside: this example illustrates why something like an operational
description in terms of marks is needed: I don't think there's any way
to reason about the above code without understanding how marks work.)
I don't think a FRESH-SYNTAX form would eliminate this issue, i.e.
reasoning about when and how to use FRESH-SYNTAX wouldn't be any easier.
Besides, something more than FRESH-SYNTAX alone would be needed,
since FRESH-SYNTAX wouldn't directly provide a way to apply fresh marks
to x and y, which are already syntax objects.
The overall problem is that the same marks need to be applied to more
than one syntax object in a given scope. A solution using a
WITH-FRESH-SYNTAX form might be more tractable, e.g.:
(lambda (x y)
(with-fresh-syntax ((x x) (y y))
(syntax
(let ((t x))
(set! x y)
(set! y t))))))))
This would transform into something equivalent to:
(lambda (x y)
(let ((stx-tmp (make-syntax-introducer)))
(with-syntax ((x (stx-tmp x)) (y (stx-tmp y)))
(stx-tmp
(syntax
(let ((t x))
(set! x y)
(set! y t)))))))
I.e. all syntax objects introduced via the WITH-FRESH-SYNTAX bindings
list, or via uses of the SYNTAX form within the WITH-FRESH-SYNTAX body,
would have the same fresh mark applied.
I can't currently make any claim about the generality of this solution,
but intuitively it seems as though something like this might be made to
work. It is intended to provide semantics similar to SRFI 72's
QUASISYNTAX form, but in the context of traditional syntax-case.
Anton