为什么'let'引入的绑定范围有限?

时间:2012-05-01 07:12:00

标签: variables lisp scope let

在Lisp中(我仍在使用SBCL学习Lisp),局部变量用let声明,范围仅在该表达式内。这是为什么?与其他命令式语言(如C / C ++ / Java ...)不同,我们可以在其功能范围内的任何位置自由使用局部变量。

3 个答案:

答案 0 :(得分:6)

再一次了解什么是什么。它基本上是一个匿名函数的应用程序“向后拼写”。

我将使用JavaScript作为插图,因为它更像是C语言,它很好地说明了这个概念。

(function(variableA, variableB){
  console.log("variableA = " + variableA);
  console.log("variableA * variableB = " + variableA * variableB);})(6, 7);

现在,让我们命名部分:从function;}是函数定义。 (definition)(arguments)是应用程序。让表达式基本上做同样的事情,即它调用带有参数的匿名函数,你在函数内部使用它作为变量。所以,如果你考虑前面的例子,用let形式重写它会产生类似的东西:

(let(variableA = 6, variableB = 7){
  console.log("variableA = " + variableA);
  console.log("variableA * variableB = " + variableA * variableB);});

(JavaScript不支持let,但是,上面不是一个有效的代码示例,但它应该是一个例子)

您还应该注意, 并非那么简单。因为在更复杂的情况下,您可能希望在构造另一个时引用其中一个参数 - 然后您将使用(let* ...),或者您希望使用函数作为此表达式的参数,然后您将使用{{1 }或(flet ...)。但总体思路是一样的。

答案 1 :(得分:4)

Lisp有一个用于引入局部变量的构造。它建立了一个范围。您可以在允许表单的任何地方使用它。这两个主要构造是LET和LET *。 Ait允许我们独立于函数定义局部变量。当我们需要局部变量时,我们不需要引入函数,并且我们使用它来使局部变量具有最小范围。

另请注意,DEFUN允许您声明局部变量:它允许参数列表中的& AUX引入它们。

答案 2 :(得分:3)

let与你所指的其他风格之间的区别仅仅是语法糖。在一种可以在任何地方引入新变量的语言中,仍然存在嵌套的作用域,只有它们在表面语法中被展平。例如

{
  x = 3;
  x++;
  y = 4;
  print "hi";
  z = 42;
}

这里只有一个范围,但范围不同。 x的范围以x = 3开头。然后y的范围以y = 4开头。如果您在该范围之前引用y,则表示您有错误。

这种事情被遗漏在Lisp之外,因为它为处理代码的代码的开发增加了很多努力。这种语言的编译器必须分析该代码并恢复显示嵌套let结构的抽象语法树结构,以便编译器的剩余通道不必重新分析代码重新发现这些信息。

在Lisp中,我们直接在那个抽象语法树结构中编写,就是这样。这使语言统一。一切都是形式,如果它是一个复合形式,它在最左边的位置有一个操作符,它以无上下文的方式确定该形式其余部分的含义。

例如,请参阅最近的一个问题:find free variables in lambda expression。如果通过绑定特殊形式(如let)或宏扩展为这些特殊形式的小型曲目,可以更轻松地查找lambda表达式中的自由变量。

另请注意,功能样式虽然不是由Lisp强制执行,但比那些类型的语言更为普遍(请注意我在虚构" {}语言中的变量定义中有一些命令性语句&# 34;。)如果您编写的代码中没有命令性陈述,那么您就不会遇到这种情况。

在功能代码中,可以let*的形式进行连续绑定:

(let* ((x 1)                    x = 1;
       (y (1+ x))               y = x + 1;
       (z (/ x y))              z = x / y;
  (sqrt z))                     return sqrt(z);

let*中的后续初始化可以引用先前的绑定。