- 当调用
f(x-1)
时,它是调用f(x) = x+10
还是f(x) = if ...
- 这是尾递归吗?
-
我应该如何使用静态/动态分配重写它?
let fun f(x) = x + 10 in let fun f(x) = if x < 1 then 0 else f(x-1) in f(3) end end
在回答您的问题之前,以下是有关您的代码的一些观察:
-
有两个函数
f
,一个在另一个内部。它们彼此不同。 -
为了减少这种混淆,您可以将内部函数重命名为
g
:let fun f(x) = x + 10 in let fun g(x) = if x < 1 then 0 else g(x-1) in g(3) end end
-
这通过以下规则清除了哪些函数调用了哪些函数:外部
f
在外部in
-end
内部定义,但立即被内部f
遮蔽。因此,对内部fun f(x) = if ...
右侧f
的任何引用都会被遮蔽,因为fun
启用自递归。任何对内in
f
的引用——end
都是阴影
-
在下面的切线示例中,如果我们使用
val
而不是fun
,则内部声明f
的右侧不会遮盖外部f
:let fun f(x) = if (x mod 2 = 0) then x - 10 else x + 10 in let val f = fn x => f(x + 2) * 2 in f(3) end end
如果在第二段代码中将内部
f
重命名为g
,它将如下所示:let fun f(x) = if (x mod 2 = 0) then x - 10 else x + 10 in let val g = fn x => f(x + 2) * 2 in g(3) end end
重要的一点是,
f(x + 2)
部分没有被重写成g(x + 2)
val
因为这意味着对f
的引用是外部f
s,而不是正在定义的f
,因为val
不是自递归定义。因此,在该定义中对f
的任何引用都必须取决于它在外部范围内的可用性。但是
g(3)
位被重写了,因为在in
-end
之间,内f
(现在g
(是阴影的。因此,无论是fun
还是val
对于let
-in
-end
的阴影无关紧要。 -
(还有一些细节。
val rec
以及我尚未详细说明的let val f = ...
的确切范围。
至于你的问题,
-
你现在应该可以回答这个问题了。提供答案的一个好方法是 1( 重命名内部函数以使其清晰,2( 使用替换手动评估代码(每行重写一次,
~>
表示重写,所以我在这里不是指 SML 运算符(。下面是我的第二个示例(不是您的代码(的外观示例:
g(3) ~> (fn x => f(x + 2) * 2)(3) ~> f(3 + 2) * 2 ~> f(5) * 2 ~> (if (5 mod 2 = 0) then 5 - 10 else 5 + 10) * 2 ~> (if (1 = 0) then 5 - 10 else 5 + 10) * 2 ~> (5 + 10) * 2 ~> 15 * 2 ~> 30
您的手动评估看起来会有所不同,并且可能得出不同的结论。
-
什么是尾递归?提供定义并询问您的代码是否满足该定义。
- 我不确定使用静态/动态分配重写它是什么意思。你必须详细说明。