2

我正在尝试在 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 ... )]))

这不起作用,因为我需要在参考点使用括号(这意味着与内置的相比,它完全没有改变let

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

那么,有没有一种方法可以重复 2 个变量syntax-rules而无需将它们包装在括号中,还是我需要使用不同的宏系统(即syntax-casedefmacro)?

4

2 回答 2

5

使用 进行此操作并不是最佳选择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))))
于 2019-06-02T23:29:50.260 回答
3

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

(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 绑定一起使用)。最好用 syntax-case 来实现这个宏。难以实现的原因是因为它有点违反为每个 AST 节点使用一对括号的想法。

于 2019-06-02T22:00:32.310 回答