Reputation: 581
I'm trying to write a macro in Scheme for Picolisp style let
expressions, let's call this macro let-slim
. In order to be more terse (like Picolisp) I want their usage to look something like this when declaring only one variable
(let-slim var-name initial-value
(display var-name))
Or something like this to declare any number of variables (note that this is pseudocode, I wouldn't actually include the elipses)
(let-slim (var-name-1 initital-value-1
var-name-2 initital-value-2
...
var-name-n initital-value-n)
(+ var-name-1 var-name-2 ... var-name-n))
The first usecase is fairly trivial to write a syntax-rules
matching pattern for, but the latter I am struggling with.
This doesn't work because only init
gets repeated
(define-syntax let-slim
(syntax-rules ()
[(_ (var init ...) body ...)
(let ((var init) ...)
body ... )]))
This doesn't work because it's considered a misplaced elipsis
(define-syntax let-slim
(syntax-rules ()
[(_ (var ... init ...) body ...)
(let ((var init) ...)
body ... )]))
And this doesn't work because I need to use parens at the reference point (which means it changes absolutely nothing as compared to the built-in let
)
(define-syntax let-slim
(syntax-rules ()
[(_ (var init) ...) body ...)
(let ((var init) ...)
body ... )]))
So, is there a way to repeat 2 variables in syntax-rules
without needing to wrap them in parens, or do I need to use a different macro system (ie syntax-case
or defmacro
)?
Upvotes: 3
Views: 479
Reputation: 1028
It's not possible to do this in one go with syntax-rules ...
feature, but you may be able to do it with syntax-rules using recursion:
(define-syntax let-slim
(syntax-rules ()
((let-slim (var-1 val-1 . rest) . body)
(let-slim var-1 val-1 (let-slim rest . body)))
((let-slim var val . body)
;; single binding case you already implemented
))
The only problem is that syntax-rules can't tell that 'var' is supposed to be a symbol. You wont get good error messages from a macro like this (for example if it's used with an odd number of var/val bindings). It may be better to implement this macro with syntax-case. The reason it's difficult to implement is because it's kind of violating the idea of using a pair of brackets for each AST node.
Upvotes: 3
Reputation: 48745
It's not optimal doing this with syntax-rules
, but since it is turing complete it can be done:
(define-syntax let-slim
(syntax-rules (pair)
((_ pair bindings () body)
(let bindings . body))
((_ pair (acc ...) (k v . rest) body)
(let-slim pair (acc ... (k v)) rest body))
((_ (elements ...) . body)
(let-slim pair () (elements ...) body))))
Upvotes: 6