所以诀窍是使用iterate 来帮助您递归地应用add。由于iterate 是一个将函数作为参数的列表组合器,如果您以非常基本的方式进行此操作,可能会更简单:例如,您可以通过递归递增/递减一来定义add:
(* Written using if-then-else *)
fun add x y =
if y = 0 then x else
if y > 0 then add (x+1) (y-1) else add (x-1) (y+1)
(* Written using mixture of pattern-matching and if-then-else *)
fun add x 0 = x
| add x y = if y > 0
then add (x+1) (y-1)
else add (x-1) (y+1)
现在,这当然是非常低效且完全没有必要的,因为我们已经有了 +,但是为了演示数字递归,这是一个如何使用 multiply 和 power 进行改进的示例(仍在假设我们还没有iterate)。
这里的通用方法是递归:由于函数有两个操作数,所以一个作为“累加结果”,另一个作为“计数变量”。因为这是一个简单的问题,您可以只使用x 和y 作为函数任务的完整环境。在稍微大一点的问题中,您可能会引入更多作为临时/中间结果的参数。
你可以用非常相似的方式写multiply:
fun multiply x 0 = 0
| multiply x y = if y > 0
then x + multiply x (y-1)
else ~x + multiply x (y+1)
这个函数解决了这个任务(虽然还是没有iterate)。
(这个multiply不是尾递归的,因为最外层的表达式(x + ...或~x + ...)不是对multiply的调用(因为调用发生在+的操作数内). 这对你来说可能不是问题,但如果是,你不能轻易写... then multiply (x + ...) (y - 1),因为当我们使用x 来累积结果时,任何后续的递归调用都增加了x ,这意味着我们不能再将x 添加到...本身...因为x 现在意味着两件事:累积结果,以及每次递归调用需要添加一次的内容。) p>
无论如何,要完成最后一步,您必须确定iterate 与我制作的add 和multiply 的共同点。当您可以发现共同点时,您可以将其隔离并调用iterate。我想修复一个可能会混淆您对iterate 的解释的空白“错误”:
fun iterate n f x = if n > 0
then iterate (n-1) f (f x)
else x; (* ^- this space! *)
添加这个空格不会改变函数的行为,但是当阅读f(f x) 时,人们很容易相信它说“将f 应用于f x”,这是错误的解释。这个函数在then 下实际上说的是“使用三个参数调用iterate:n-1、f 和f x;因为n-1 的绑定不如函数应用程序紧密,而f x 是 函数应用程序(它是左关联的),我们在它们周围添加括号;这对于f 不是必需的。”
在add 和multiply 中,y 被用作计数变量,而在iterate 中它是n。所以名称和位置发生了变化,这意味着基于iterate 的multiply 必须将x 和y 放在正确的位置。至于确定f 的值:将x 添加到结果中的函数怎么样?您可以使用 lambda、(fn z => ...) 或使用函数 add 的部分应用来表达此函数。
最后,power 也是同样的问题:
fun power x 0 = 1
| power x n = if n > 0
then x * power x (n-1)
else raise Fail "Cannot express 1/x^n as integer"
由于整数没有很好的解决方案,你要么必须切换到real类型来表达1/x^n,你也可以翻转条件并在开始递归之前将n < 0 的情况排除在外:
fun power x n =
if n < 0 then raise Fail "Cannot express 1/x^n as integer"
else let fun go result 0 = result
| go result i = go (result * x) (i-1)
in go 1 n
end
内部函数go看起来非常像上面的add,除了x变成了result,1变成了add,+变成了*,还有没有否定案例 (if y > 0 ... else ...)。
这意味着您实际上可以使用iterate 而不是go,只要您为iterate n f x 找到好的值:
-
n 应该是什么? (需要倒计时。)
-
f 应该是什么? (执行逐步计算的东西。)
-
x 应该是什么? (在逐步计算中应用的东西。)
(...全部以iterate 表示;在power 函数及其范围内的参数的上下文中,它们可能被称为其他名称。)