用于创建本地绑定的'let'或'letrec'和'define'之间有什么区别?

Mat*_*ick 3 variables scheme scope letrec

我不明白它们之间的区别(对于人为的例子而言):

(define average
  (lambda (elems)

   (define length
     (lambda (xs)
      (if (null? xs)
          0
          (+ 1 (length (cdr xs))))))

   (define sum
     (lambda (xs)
      (if (null? xs)
          0
          (+ (car xs) (sum (cdr xs))))))

   (define total (sum elems))

   (define count (length elems))

   (/ total count)))
Run Code Online (Sandbox Code Playgroud)

(define average
  (lambda (elems)
   (letrec ((length
              (lambda (xs)
               (if (null? xs)
                   0
                   (+ 1 (length (cdr xs))))))

            (sum
              (lambda (xs)
               (if (null? xs)
                   0
                   (+ (car xs) (sum (cdr xs))))))

            (total (sum elems))

            (count (length elems)))

     (/ total count))))
Run Code Online (Sandbox Code Playgroud)

据我所知,他们都创建了一个新的范围,并在该范围内创建了4个局部变量,这些变量相互引用并与自身相关,并评估并返回一个主体.

我在这里遗漏了什么,或者是letrecscoped defines的同义词?

我知道这可能是依赖于实现的; 我试图了解Lisps的基本原理.

Chr*_*ung 6

你是正确的,你的代码defineletrec版本之间有相似之处.然而,魔鬼在细节中.在R5RS中,内部define具有letrec语义.在R6RS中,内部define具有letrec*语义.

有什么不同?您的代码实际上只突出了这种差异.至于哲浩的回答中提到,您的定义totalcount内部相同letreclengthsum不正确:lengthsum不能保证通过你正在评估值的时间约束(length elems)(sum elems),因为这些变量的结合是不能保证是左到右.

letrec*类似于letrec,但具有从左到右的保证.所以,如果你改变letrecletrec*,那就没关系了.

现在,回到我最初的评论:因为R5RS的内部define使用letrec语义,即使你define的代码版本在R5RS实现下也是不正确的,但在具有letrec*语义的R6RS实现下也没问题.