在递归函数调用期间使用Let表达式时,有关局部变量范围的问题

时间:2019-06-13 11:03:30

标签: recursion ml

我在递归调用函数时试图找出当前的动态环境并绑定了函数中的局部变量的值时遇到了一些麻烦。这不仅是我在ML中遇到的问题,甚至在JAVA中,我对递归调用期间的变量范围感到非常困惑。

fun examplefunction(x:int,ys:int list)=
if null (tl ys)
then 0
else
let
  val temp=0
  val temp=temp +(hd ys)
  val tail= (tl ys)
  val k=1
in

  if x>temp andalso temp+(hd tail)>=x

  then k

  else k+examplefunction(x,tl ys)

end

我很难理解在递归调用期间如何更新temp变量(如果我假设输入int列表足够大)。例如在这种情况下

x = 5和ys = [2,1,3],我通过以下方式调用函数

examplefunction(5,[2,1,3]);

在这种情况下,第2行中的(tl ys)不为空

并因此被执行,在第6行中,变量temp被绑定到整数0,在随后的第7行中,它被屏蔽,在新的动态环境中,它被绑定到2。变量tail被绑定到int列表[1],变量k绑定到1。

现在在“ in”(从第10行开始)中,如果in 12行上的表达式为false,则执行第16行中的else,以递归方式调用该函数

examplefunction(5,[1,3])

我想了解这个函数调用“ examplefunction(5,[1,3])”的环境吗?

当该递归函数调用被执行时,在第6行中,在上一个调用中为2的temp变量被0遮盖,然后被0 + hd [1,3] = 0 + 1 = 1遮盖。 >

这对我来说非常混乱,在编写家庭作业中的某些功能时确实是一个很大的障碍。如果问题不清楚,请告诉我。

1 个答案:

答案 0 :(得分:0)

环境将名称与函数x,ys的参数以及let子句的主体中的名称,temp,tail和k(在这种情况下)相关联。 let内的每个val声明都会扩展环境,将名称绑定到子表达式。

因此,在查看examplefunction时,在其中评估函数主体的环境将x和ys绑定到调用该函数的任何内容。在您的第一个示例中:x绑定到5,ys绑定到[2,1,3]。

在评估if分支和then分支时,不会向环境添加任何内容。在else分支中,有一个let子句,它将为环境添加一些新的绑定。

第一个是temp =0。在表达式的这一点上,评估环境为x,ys和现在的temp。

接下来,温度回弹到子表达式temp + hd ys。此时,环境不会绑定任何新名称,但是绑定到temp的表达式已更改。

let子句中的下一个绑定是tl ys的尾部。这会为环境尾部添加一个新名称。

最后,k绑定到1。环境现在将变量x,ys,temp,tail和k绑定到某些子表达式。当使用参数x = 5和ys = [2,1,3]调用时,这些绑定将是:temp = 0 + hd ys = 2,tail = tl ys = [1,3],k = 1。

然后评估下一个if-then-else子表达式,取决于布尔x> temp和temp +(hd tail)> = x是否为true,是否可以递归调用examplefunction。

重要的是,如果确实以递归方式调用它,则环境不会绑定temp,tail和k,因为它们对于let子句来说是局部的。如前所述,在递归调用中,x将绑定到x,ys将绑定到tl ys,我们将重新开始相同的过程。

要点:

  1. 环境将名称与表达式关联。
  2. let子句中的函数和val声明的参数在表达式求值期间向环境添加了本地绑定。
  3. 以递归方式调用该函数时,绑定在函数主体内部的let表达式内的任何内容都不会绑定到以递归调用开始