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

时间:2018-11-27 15:14:03

标签: scheme racket r6rs define-syntax r7rs

我目前正在学习一些r7rs,并且正在尝试实现如下宏“ begin”:

(begin0 expr0 expr1 ... expr2)

expr为正则表达式(例如(set!x(+ x 1)))

然后begin0作为一个宏,它计算所有表达式,但仅返回expr1结果。

例如:

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

必须返回2018

我首先创建了一个begin函数:

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

现在,我试图了解如何返回“ 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))))))

我希望它是可以理解的,谢谢您的回答。

2 个答案:

答案 0 :(得分:2)

这是可以做到的,但是宏会干扰到您无法像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的持续时间内可用。对于此问题,我没有解决方法,因为它要求您能够从结束处进行全局define

begin1是相当奇怪的功能。在Racket和其他Scheme方言中,我们有begin0返回第一个表达式的结果。这是非常有用的。例如。这是一个柜台:

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

在球拍begin0中是一个原始字符。因此,它是完全扩展程序中支持的一种形式,因此可以用C来实现,就像begin ..

答案 1 :(得分:-1)

因此,我找到了一种可行的方法,尽管我们只能询问立即值的条件,但我没有:

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