Coding style 为什么let优先在方案中定义?
我总是这样写我的计划程序(并且看到它们被编写):Coding style 为什么let优先在方案中定义?,coding-style,scheme,let,Coding Style,Scheme,Let,我总是这样写我的计划程序(并且看到它们被编写): (define (foo x) (let ((a ...)) ((b ...)) ...)) 我的一个学生写道: (define (foo x) (define a ...) (define b ...) ...) 两者的结果相同。我理解行为上的差异:第一个创建一个指向过程应用程序框架的新框架,而后者直接修改过程应用程序框架。后者将产生稍好的性能 另一个区别是前者避免在过程体中的指令序列之前使用隐式的be
(define (foo x)
(let ((a ...))
((b ...))
...))
我的一个学生写道:
(define (foo x)
(define a ...)
(define b ...)
...)
两者的结果相同。我理解行为上的差异:第一个创建一个指向过程应用程序框架的新框架,而后者直接修改过程应用程序框架。后者将产生稍好的性能
另一个区别是前者避免在过程体中的指令序列之前使用隐式的begin
为什么前一种是标准样式?实际上,两种样式都可以 后者也不一定“直接修改程序应用框架”;内部定义与
letrec
(适用于R5RS兼容系统)或letrec*
(适用于R6RS-和R7RS兼容系统)处理相同。因此,您的第二个示例实际上与以下示例相同:
(define (foo x)
(letrec* ((a ...)
(b ...))
...))
事实上,举一个例子,Racket将内部定义重写为其等价的
letrec*
表达式,因此性能上没有差异(当然,除了let
和letrec*
之间的差异之外)。这不是完全等价的<过程体中的code>define更像是letrec
,因此您可能会惊讶地发现,在define
中的值绑定尚未完成且过程体尚未执行之前,您无法使用该值。假设你想做x+y*z:
(define (test x y z)
(let ((ytimesz (* y z)))
(let ((sum (+ x ytimesz)))
(dosomething sum))))
这里之所以有嵌套let,是因为无法在创建时在同一let中访问ytimesz
。我们有另一种特殊的形式,那就是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
和#!球拍
完全可以,因为它被定义为letrec*
在#中!然而,R5RS根本不起作用。重写按letrec
进行,它将所有变量(ytimesz
和answer
)初始化为未定义的值,然后将表达式的计算分配给设置之前的临时变量代码>-将变量转换为临时值的值,以确保所有使用的任何变量最终都是未定义的值,有些甚至是信号错误(Racket在R5RS模式下运行。对于在调用时计算主体中绑定的lambda表达式,这没有问题,它适用于这些letrec
,而internaldefine
最初用于
我使用define
来存储简单的值和过程。第二,我想我需要使用一个预先计算的值,我可能会将整个过程重写为let*
或者将define
和一个简单的let组合起来。谢谢你纠正了我的误解。我们确实在使用Racket。也谢谢你在风格上的链接NK很多。你知道为什么过程中的定义与顶级定义的行为不同吗?R6RS内部定义,如R7RS内部定义,使用letrec*
,而不是letrec
@espertus,因为Scheme语言定义了两种不同的含义来定义
,一种用于顶级绑定,另一种基本上用于语法糖letrec*
。这是适合您的方案。:-@ChrisJester Young固定R6RS。顶层差异一定是因为顶层实际上不是一个框架或仅仅是一个框架。顶层定义会改变“顶层框架”,但会在以后进行计算,然后再上一个define
使其变得特别?