为啥让首选在Scheme中定义?
Posted
技术标签:
【中文标题】为啥让首选在Scheme中定义?【英文标题】:Why is let preferred to define in Scheme?为什么让首选在Scheme中定义? 【发布时间】:2014-03-18 22:40:10 【问题描述】:我一直是这样编写我的 Scheme 程序(并看到它们编写的):
(define (foo x)
(let ((a ...))
((b ...))
...))
我的一个学生写道:
(define (foo x)
(define a ...)
(define b ...)
...)
两者都给出相同的结果。我理解行为上的差异:第一个创建一个指向程序应用程序框架的新框架,而后者直接修改程序应用程序框架。后者会产生更好的性能。
另一个区别是前者避免在过程体中的指令序列之前使用隐式begin
。
为什么是以前的标准样式?
【问题讨论】:
【参考方案1】:其实这两种风格都很好。 In fact, some people prefer to use internal definitions.
另外,后者也不一定是“直接修改程序应用框架”;内部定义与letrec
(对于 R5RS 兼容系统)或 letrec*
(对于 R6RS 和 R7RS 兼容系统)处理相同。因此,您的第二个示例实际上与以下示例相同:
(define (foo x)
(letrec* ((a ...)
(b ...))
...))
事实上,举个例子,Racket 将内部定义重写为等效的letrec*
表达式,因此性能没有差异(当然,除了let
和letrec*
之间的差异之外)。
【讨论】:
感谢您纠正我的误解。我们确实在使用 Racket。 也感谢您提供有关样式的链接。【参考方案2】:它并不完全等价。过程主体中的define
更像是letrec
,因此您可能会感到惊讶,在所有这些都完成并且要执行过程主体之前,您不能使用define
中绑定的值。想象一下你想做 x + y * z:
(define (test x y z)
(let ((ytimesz (* y z)))
(let ((sum (+ x ytimesz)))
(dosomething sum))))
你在这里有一个嵌套的 let 的原因是因为ytimesz
不能在创建它的同一个 let 中访问。我们有另一个特殊的表格let*
(define (test x y z)
(let* ((ytimesz (* y z)) (sum (+ x ytimesz)))
(dosomething sum)))
letrec
和letrec*
相似,但允许递归,因此在 lambda 中,您可以调用其他绑定成员之一或自身。现在,根据您使用的 Scheme 版本,您将在编写时获得其中之一:
(define (test x y z)
(define ytimesz (* y z))
(define answer (+ x ytimesz)) ;might work, might not
(dosomething answer))
在#!R7RS
、#!R6RS
和#!Racket
中完全可以,因为它被定义为letrec*
。
但是,在#!R5RS
中,它根本不起作用。重写以letrec
完成,它将所有变量(ytimesz
和answer
)初始化为一个未定义的值,然后在set!
将变量赋值给临时值,以确保对它们中的任何一个的所有使用最终都作为未定义的值,甚至一些信号错误(Racket 在 R5RS 模式下执行。对于在调用时评估主体中的绑定的 lambda 表达式,这没问题,并且它是为这些letrec
和内部define
原本打算的。
我使用define
来存储简单的值和过程。第二个我认为我需要使用预先计算的值,我可能会将整个内容重写为 let*
或组合 define
和简单的 let
。
【讨论】:
非常感谢。你知道为什么在过程中定义的行为与顶层不同吗? R6RS 内部定义,和 R7RS 一样,使用letrec*
,而不是letrec
。
@espertus 因为Scheme 语言为define
定义了两种不同的含义,一种用于***绑定,另一种本质上是letrec*
的语法糖。这就是你的计划。 :-)
@ChrisJester-Young 修复了 R6RS。顶层的区别一定是因为现实中的顶层不是一帧,也不是一帧。***定义会改变“***框架”,但会在之前的 define
之后进行评估,使其特别?以上是关于为啥让首选在Scheme中定义?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Clojure 成语更喜欢返回 nil 而不是像 Scheme 这样的空列表?
为啥 Scheme `filter` 表单不能“按顺序”处理列表元素?