4

我正在阅读r5rs方案标准,发现begin()其实是一个库语法,也就是说可以由scheme自己定义,标准在标准末尾给出了实现。

我按照 r5rs 使用如下定义语法实现了 begin():

(define-syntax mybegin
  (syntax-rules ()
                ((mybegin expr) expr)
                ((mybegin expr1 expr2 ...)
                 (let ((x expr1))
                   (mybegin expr2 ...)))))

然后我尝试使用函数来实现它,这是我的代码:

(define begin-func
  (lambda (expr1 expr2)
    ((lambda (x) expr2) expr1)))

这是我的测试用例:

(define x 3)
(define y 3)
(mybegin
  (set! x 4)
  (set! x 5))
(begin-func
  (set! y 4)
  (set! y 5))

我使用#lang 方案在 MIT-SCHEME 和 Racket 中运行我的代码,x 在 MIT-SCHEME 和 Racket 中都是 5,但是,y 在 MIT-SCHEME 中是 4,​​而在 Racket 中是 5

所以,这是我的问题:

  1. 我们真的可以使用纯函数方案实现 begin() 吗?
  2. 我的代码有什么问题吗,无论是使用宏的代码还是使用函数的代码?
  3. 为什么相同的代码在 MIT-SCHEME 和 Racket 中表现不同?
4

1 回答 1

3

begin是一种特殊形式,按顺序计算每个元素,并计算到最后一个表达式。您永远不需要begin纯函数式方案,但可以begin在没有begin特殊形式或嵌入lambda形式或亲属的方案中以函数方式获得类似的功能。这只是一个例外,define它就在其中。 define在顶级开始将在全球范围内定义,而模仿将使用程序来按顺序进行评估,define然后只会成为本地绑定,当程序超出范围时才会终止。

begin必须将其定义为语法,因为如果您执行以下过程:

(define (mybegin . args)
  ...)

调用时的所有参数mybegin都将按照实现特定的顺序进行评估。该报告说评估需要随之而来,这样您就不会看到一个实现一次获得 4 个,另一个获得 5 个,但是您会看到其中一个每次都在相同的过程中发生。不能保证评估也会在两个不同的过程中以相同的顺序发生,但是许多 Scheme 实现通常以相同的顺序进行。

Racket总是按顺序评估参数,这没关系,因为报告说您可以随心所欲地进行,而 MIT 至少有时会以相反的顺序进行评估。

于 2014-08-11T08:20:47.510 回答