区分Scheme的let、let*和letrec三种不同的let形式在实践中是否有用?
我目前正在开发一种lisp风格的语言,支持这3种形式,但我发现:
1. 常规的“let”是最低效的形式,必须要转换为立即调用的lambda形式,生成的指令几乎相同。此外,我很少需要使用这种形式。
2. let*(顺序绑定)似乎是最实用和经常使用的形式。此形式可以转换为一系列嵌套的“let”,每个环境存储一个变量。但这又是非常低效的,浪费空间和查找时间。
3. letrec(递归绑定)可以高效地实现,只要没有初始化器表达式引用未绑定的变量。通常情况下,所有初始化器都是lambda表达式且上述条件成立。
问题是:既然letrec可以有效地实现,并且还包含了let*的行为,而常规let并不经常使用,可以将默认的“let”行为设置为当前的“letrec”,并摆脱原始的“let”吗?
我目前正在开发一种lisp风格的语言,支持这3种形式,但我发现:
1. 常规的“let”是最低效的形式,必须要转换为立即调用的lambda形式,生成的指令几乎相同。此外,我很少需要使用这种形式。
2. let*(顺序绑定)似乎是最实用和经常使用的形式。此形式可以转换为一系列嵌套的“let”,每个环境存储一个变量。但这又是非常低效的,浪费空间和查找时间。
3. letrec(递归绑定)可以高效地实现,只要没有初始化器表达式引用未绑定的变量。通常情况下,所有初始化器都是lambda表达式且上述条件成立。
问题是:既然letrec可以有效地实现,并且还包含了let*的行为,而常规let并不经常使用,可以将默认的“let”行为设置为当前的“letrec”,并摆脱原始的“let”吗?
let
下,对某个X
的引用不一定会指向文本上最近的定义,而可能是之前的一个。你正在阅读的代码不一定是正确的:如果你有(let ((a (foo)) (b (+ a (bar))) ...)
,你知道a
和b
是独立的;但这是 意图 吗?也许那个a
应该指向文本上最近的定义。 - Kaz