【问题标题】:Hygienic macro r7rs : Return second expression value卫生宏 r7rs:返回第二个表达式值
【发布时间】:2019-04-29 08:53:35
【问题描述】:

我目前正在学习一些 r7rs,我正在尝试实现一个宏“开始”,如下所示:

(begin0 expr0 expr1 ... expr2)

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

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

例如:

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

2018年一定要回归

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

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

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

【问题讨论】:

    标签: scheme racket r6rs define-syntax r7rs


    【解决方案1】:

    所以,我找到了一种可能的方法,尽管我们可以只询问立即值的条件:

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

    【讨论】:

    • 在这里,除了第二个表达式之外,您不会评估任何其他内容。我假设(begin1 (display "h") (display "i") (display "!")) 应该打印“嗨!”结果是#<undefined>,但事实并非如此。
    【解决方案2】:

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

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

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

    【讨论】:

    • 感谢您的回答,这正是我所需要的!非常感谢您的解释,我不明白该怎么做,但似乎更清楚了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    • 2021-11-29
    • 1970-01-01
    • 1970-01-01
    • 2014-12-17
    • 2016-02-03
    相关资源
    最近更新 更多