gpt4 book ai didi

scheme - letrec/letrec* 比带有内部定义或命名的 let 更好的示例?

转载 作者:行者123 更新时间:2023-12-04 17:39:04 28 4
gpt4 key购买 nike

Kent Dybvig 在 The Scheme Programming Language for letrec 和 letrec* 中给出的两个示例是:

(letrec ([sum (lambda (x)
(if (zero? x)
0
(+ x (sum (- x 1)))))])
(sum 5))


(letrec* ([sum (lambda (x)
(if (zero? x)
0
(+ x (sum (- x 1)))))]
[f (lambda () (cons n n-sum))]
[n 15]
[n-sum (sum n)])
(f))

第一个也可以写成命名的let:
(let sum ([x 5]) 
((lambda (x)
(if (zero? x)
0
(+ x (sum (- x 1))))) x))

第二个可以写成带有内部定义的let:
(let ()
(define sum (lambda (x)
(if (zero? x)
0
(+ x (sum (- x 1))))))
(define f (lambda () (cons n n-sum)))
(define n 15)
(define n-sum (sum n))
(f))

letrec/letrec* 形式似乎并不比命名的 let 或带有内部定义形式的 let 更简洁或更清晰。

有人可以向我展示一个示例,其中 letrec/letrec* 确实改进了代码或者是必要的,而不是使用内部定义命名的 let 或 let。

最佳答案

是的,第一个示例可以使用命名 let 重写。 ,但请注意,不需要 lambda在那里形成:

(let sum ([x 5])
(if (zero? x)
0
(+ x (sum (- x 1)))))

这种转换有点误导 - 如果您定义一个“循环函数”(在广义的非尾递归意义上)并立即在已知输入上使用它,则可以这样做。但是通常,当您看到您给出的示例时,其目的是展示局部函数的定义和使用,因此可以进行这种转换只是因为它是一个用于演示的玩具示例。

其次,注意一个名为 let通常是 不是 原始形式——几乎所有 Scheme 实现都使用的实现策略是将该形式扩展为 letrec .因此,了解 letrec 仍然是一个好主意。如果你想了解命名- let s。 (这是一个基本特征:能够通过递归作用域进行自引用。)

最后,您给出的带有内部定义的示例类似于命名- let。 s:它是一种语法糖,扩展为 letrec (可以是正确的 letrec 或带有 R5RS 的 letrec*,并且在 R6RS 中必须是 letrec*)。所以为了了解它是如何工作的,你需要了解 letrec .另请注意,某些使用严格的实现 letrec也会在你的第二个例子中呕吐,并提示 sum未定义。正是这种句法加糖是 letrec* 的主要论点。 R6RS 中采用的语义:很多人喜欢使用内部定义,但是存在一个问题,即顶层定义允许使用以前的定义,但内部定义以一种意想不到的方式不太方便。与 letrec* , 内部定义像顶级定义一样工作。 (更准确地说,它们就像顶级禁止重新定义一样工作,这意味着它们实际上就像模块顶级定义。)

(另请注意,(a)Racket 和 Chez 都扩展了内部主体以允许混合定义和表达式,这意味着扩展同样简单。)

关于scheme - letrec/letrec* 比带有内部定义或命名的 let 更好的示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8663140/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com