为啥让首选在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* 表达式,因此性能没有差异(当然,除了letletrec* 之间的差异之外)。

【讨论】:

感谢您纠正我的误解。我们确实在使用 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)))

letrecletrec* 相似,但允许递归,因此在 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 完成,它将所有变量(ytimeszanswer)初始化为一个未定义的值,然后在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` 表单不能“按顺序”处理列表元素?

Scheme - 嵌套定义混淆

在 Scheme / Racket 中 let 的 lambda 定义是啥? [复制]

在 scheme 中定义 goto

为啥 SwiftUI 中的 URL Scheme/onOpenURL 总是打开一个新窗口?