我不明白它们之间的区别(对于人为的例子而言):
(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)))
和
(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))))
据我所知,他们都创建了一个新范围,并在该范围内创建了4个局部变量,这些变量相互引用并与自身相关,并评估并返回一个正文。
我在这里遗漏了什么,或letrec
是否与范围define
同义?
我知道这可能是依赖于实现的;我试图了解Lisps的基本原理。
答案 0 :(得分:6)
您的代码的define
和letrec
版本之间存在相似之处。然而,魔鬼在细节中。在R5RS中,internal define
has letrec
semantics。在R6RS中,internal define
has letrec*
semantics。
有什么区别?您的代码实际上只是强调了这种差异。正如哲浩的回答所提到的那样,total
和count
在与letrec
和length
相同的sum
内的定义不正确:length
和{ {1}}不能保证在您评估sum
和(length elems)
的值时受到约束,因为这些变量的绑定不能保证从左到右。< / p>
(sum elems)
与letrec*
类似,但具有从左到右的保证。因此,如果您将letrec
更改为letrec
,那就没关系。
现在,回到我最初的评论:因为R5RS的内部letrec*
使用define
语义,即使您的letrec
版本的代码在R5RS实现下也是不正确的,但它会是好吧,在R6RS实现下,它具有define
语义。
答案 1 :(得分:4)
let / letrec和define都将创建本地范围的定义。但是,当你不在内部和隐式begin语句时,让/ letrec更方便。例如,以下代码使用let宏。
(define (test) (let ((x 1)) x))
使用本地作用域定义的相同代码将是
(define test (lambda () (define x 1) x))
这是一个人为的例子,但通常使用let宏来进行局部绑定被认为更有用。
此外,您的示例代码未正确使用letrec。你不需要letrec声明中的定义(实际上它们确实不应该存在)。