卫生宏 r7rs : Return 第二个表达式值

Hygienic macro r7rs : Return second expression value

我目前正在学习一些 r7rs,我正在尝试实现一个宏 'begin',如下所示:

(begin0 expr0 expr1 ... expr2)

expr是一个正则表达式(如(set!x(+ x 1)))

并且 begin0 作为一个宏计算所有表达式,但 return 仅计算 expr1 结果。

例如:

(let ((year 2017))
(begin1 (set! year (+ year 1))
  year
  (set! year (+ year 1))
  year)) 

必须 return 2018

我先创建了一个开始函数:

(define-syntax begin0
 (syntax-rules ()
  ((begin-0 body-expr-0 body-expr-1 ...)
   (let ((tmp body-expr-0)) body-expr-1 ... tmp))))

现在,我正在尝试了解如何才能 return "body-expr-1" 的价值? 我已经完成了以下代码,但它说我缺少一些省略号而且我不知道该怎么做。

(define-syntax begin1
  (syntax-rules ()
    ((begin1 body-expr-0 body-expr-1 ... body-expr-2)
     (let ((tmp body-expr-0) body-expr-1 ... tmp)
       (cond (eq? tmp body-expr-1)
              (begin . tmp))))))

我希望它足够理解,感谢您的回答。

所以,我找到了一种可能的方法,虽然我们可以只询问立即值的条件,但我没有找到:

(define-syntax begin1
  (syntax-rules ()
    ((begin1 body-expr-0 body-expr-1 body-expr-2 ...)
       (if body-expr-1
          (write body-expr-1)))))

这可以做到,但是宏会干扰你不能用 begin1 做所有事情,就像 begin

(define-syntax begin1
   (syntax-rules ()
     ((_ expr0 expr1 exprn ...)
      (begin
        expr0
        (let ((result expr1))
          exprn ...
          result)))))

不起作用的代码是这样的:

(begin1
  (define global1 10)
  test3
  (define global2 20))

原因很明显。它扩展为:

(begin1
  (define global1 10)
  (let ((result~1 test3))
    (define global2 20)
    result~1))

第二个 define 将更改为 letrec,这样变量 global2 仅在 let 期间可用。我没有解决这个问题,因为它要求您能够从闭包中执行 global define

begin1 是一个相当奇怪的特征。在 Racket 和其他 Scheme 方言中,我们有 begin0 第一个表达式的结果 returns 。这非常有用。例如。这是一个计数器:

(define (get-counter from)
  (lambda ()
    (let ((tmp from))
      (set! from (+ from 1))
      tmp)))

begin0:

(define (get-counter from)
  (lambda ()
    (begin0 
      from
      (set! from (+ from 1)))))

在 Racket 中 begin0 是原语。所以它是完全扩展程序中支持的一种形式,因此在 C 中实现,就像 begin..