方案:如何在语法规则中扩展具有多个变量且无括号的模式

时间:2019-06-02 21:14:59

标签: macros scheme syntax-rules

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

(let-slim var-name initial-value
  (display var-name))

或者类似这样的声明任何数量的变量(请注意,这是伪代码,我实际上不会包含省略号)

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

第一个用例对于为其编写syntax-rules匹配模式来说是微不足道的,但是我正在努力解决后者。

这不起作用,因为只有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相比,它绝对没有改变)

(define-syntax let-slim
  (syntax-rules ()
    [(_ (var init) ...) body ...)
     (let ((var init) ...)
       body ... )]))

因此,有没有一种方法可以在syntax-rules中重复两个变量而无需将它们包装在括号中,或者我是否需要使用其他宏系统(即syntax-casedefmacro )?

2 个答案:

答案 0 :(得分:2)

使用语法规则...功能无法一次性做到这一点,但是您可以使用递归使用语法规则来做到这一点:

(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绑定一起使用)。最好在语法大小写的情况下实现此宏。之所以难以实现,是因为它违反了为每个AST节点使用一对括号的想法。

答案 1 :(得分:2)

使用syntax-rules进行此操作不是最佳方法,但是由于它已完成,可以做到:

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