Functional programming 使用scheme本身实现内置的scheme函数begin(),相同的代码在MIT-scheme和Racket中的行为不同?

Functional programming 使用scheme本身实现内置的scheme函数begin(),相同的代码在MIT-scheme和Racket中的行为不同?,functional-programming,scheme,racket,r5rs,Functional Programming,Scheme,Racket,R5rs,我正在阅读r5rs scheme标准,发现begin()实际上是一种库语法,这意味着它可以由scheme本身定义,该标准在标准末尾给出了一个实现 我遵循R5R使用如下定义语法实现了begin(): (define-syntax mybegin (syntax-rules () ((mybegin expr) expr) ((mybegin expr1 expr2 ...) (let ((x ex

我正在阅读r5rs scheme标准,发现begin()实际上是一种库语法,这意味着它可以由scheme本身定义,该标准在标准末尾给出了一个实现

我遵循R5R使用如下定义语法实现了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))
我在MIT-SCHEME和Racket中使用#lang SCHEME运行代码, 在MIT-SCHEME和Racket中x都是5,然而,在MIT-SCHEME中y是4,但在Racket中是5

所以,我的问题是:

  • 我们真的可以使用pure实现begin()吗 功能方案
  • 我的代码中是否有任何错误,包括使用宏的代码和使用宏的代码 功能
  • 为什么相同的代码在MIT-SCHEME和Racket中表现不同

  • begin
    是一种特殊形式,它按顺序计算每个元素,并计算到最后一个表达式。在纯功能方案中,您永远不需要使用
    begin
    ,但在没有将
    begin
    作为特殊形式或嵌入
    lambda
    表单或亲属的方案中,可以以功能方式获得与
    begin
    类似的功能。只有一个例外,那就是
    define
    <顶级begin中的code>define将在全局范围内定义,而模拟将使用过程按顺序进行评估,
    define
    将仅成为局部绑定,当过程超出范围时,该绑定将失效

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

    (define (mybegin . args)
      ...)
    
    调用
    mybegin
    时,所有参数都将按照特定于实现的顺序进行计算。报告说,评估需要是后续的,这样您就不会看到一个实现一次得到4个,另一次得到5个,但是您会看到,对于同一个过程,每次都会发生其中一个。不能保证在两个不同的过程中也会以相同的顺序进行评估,但许多方案实现通常以相同的顺序进行评估


    Racket总是按顺序计算参数,这是可以的,因为报告说你可以随心所欲,而麻省理工学院至少有时会按相反的顺序进行计算。

    @benrudgers没有纯函数式方案,但你可以用纯函数式的方式对方案进行编程。他确实在第一个问题中提到了功能方案,并避免在
    let
    中使用显式
    begin
    ,而是嵌套
    let
    表单,就好像
    let
    只处理尾部调用一样。这使得这个问题更有趣,因为它表明我们可以用宏来降低函数式语言的功能。