Macros Scheme:如何在没有paren的情况下扩展语法规则中具有多个变量的模式

Macros Scheme:如何在没有paren的情况下扩展语法规则中具有多个变量的模式,macros,scheme,syntax-rules,Macros,Scheme,Syntax Rules,我正试图在Scheme中为Picolisp样式的let表达式编写一个宏,我们称这个宏为let slim。为了更简洁(比如Picolisp),我希望在只声明一个变量时,它们的用法看起来像这样 (let-slim var-name initial-value (display var-name)) 或者像这样声明任意数量的变量(请注意,这是伪代码,我实际上不包括省略号) 第一个用例编写语法规则匹配模式非常简单,但我正在努力解决后者 这不起作用,因为只有init被重复 (define-synta

我正试图在Scheme中为Picolisp样式的
let
表达式编写一个宏,我们称这个宏为
let slim
。为了更简洁(比如Picolisp),我希望在只声明一个变量时,它们的用法看起来像这样

(let-slim var-name initial-value
  (display var-name))
或者像这样声明任意数量的变量(请注意,这是伪代码,我实际上不包括省略号)

第一个用例编写
语法规则
匹配模式非常简单,但我正在努力解决后者

这不起作用,因为只有
init
被重复

(define-syntax let-slim
  (syntax-rules ()
    [(_ (var init ...) body ...)
     (let ((var init) ...)
       body ... )]))
这不起作用,因为它被认为是一个放错位置的省略

(define-syntax let-slim
  (syntax-rules ()
    [(_ (var ... init ...) body ...)
     (let ((var init) ...)
       body ... )]))
这不起作用,因为我需要在参考点使用parens(这意味着与内置的
let
相比,它完全没有变化)


那么,有没有办法在
语法规则
中重复两个变量,而不需要将它们包装在括号中,或者我需要使用不同的宏系统(即
语法大小写
defmacro
)?

使用语法规则
功能一次完成这项工作是不可能的,但是,您可以使用递归的语法规则来实现这一点:

(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
     ))

唯一的问题是语法规则无法判断“var”应该是一个符号。这样的宏(例如,如果它与奇数个var/val绑定一起使用),您将无法获得良好的错误消息。最好用语法case实现这个宏。难以实现的原因是,它有点违反了为每个AST节点使用一对括号的想法。

使用
语法规则执行此操作不是最佳选择,但由于它是图灵完成的,因此可以执行:

(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))))

我不相信您的示例代码按原样工作。在第一种情况下,主体应该位于let slim的递归调用中,并以这种方式编写,它似乎最终扩展为对(let slim().body)的引用,该引用没有合适的匹配大小写。我通过添加这样一个案例来实现它,但这将允许最终用户在任何时候使用(let slim().body),这可能有点愚蠢。我想我会研究使用syntax-case,但如果您知道最后一个问题的解决方案,请告诉我。
(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
     ))
(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))))