【发布时间】:2023-03-13 12:04:01
【问题描述】:
我正在阅读 Brain harvey 的计算机编程结构和解释。我遇到了这个问题,我不知道该怎么做。
我们如何在 Scheme 中用 lambda 编写递归过程?
【问题讨论】:
标签: recursion lambda scheme sicp
我正在阅读 Brain harvey 的计算机编程结构和解释。我遇到了这个问题,我不知道该怎么做。
我们如何在 Scheme 中用 lambda 编写递归过程?
【问题讨论】:
标签: recursion lambda scheme sicp
TL;DR:使用命名let(如果您正在立即执行递归函数)或rec(如果您要保存递归函数以供以后执行)。
通常的方法是使用letrec,或者在幕后使用letrec,例如命名为let 或rec。这是使用letrec 的(factorial 10) 版本:
(letrec ((factorial (lambda (x)
(if (< x 1) 1
(* (factorial (- x 1)) x)))))
(factorial 10))
同样的事情使用命名let:
(let factorial ((x 10))
(if (< x 1) 1
(* (factorial (- x 1)) x)))
这里的关键理解是两个版本完全相同。命名为let 只是一个扩展为letrec 形式的宏。因此,由于命名为 let 的版本较短,这通常是编写递归函数的首选方式。
现在,您可能会问,如果您想直接返回递归函数对象,而不是执行它怎么办?在那里,你也可以使用letrec:
(letrec ((factorial (lambda (x)
(if (< x 1) 1
(* (factorial (- x 1)) x)))))
factorial)
这里也有一个简写,虽然没有使用命名let,而是使用rec:
(rec (factorial x)
(if (< x 1) 1
(* (factorial (- x 1)) x)))
在这里使用rec 的好处是您可以将函数对象分配给一个变量并在以后执行它。
(define my-fact (rec (factorial x)
(if (< x 1) 1
(* (factorial (- x 1)) x))))
(my-fact 10) ; => 3628800
创建递归函数的更理论和“纯粹”的方法是使用Y combinator。 :-) 但是大多数实际的 Scheme 程序都没有使用这种方法,所以我不会进一步讨论。
【讨论】:
不需要写两次阶乘体;)
(((lambda (f)
(lambda (x)
(f f x)))
(lambda (fact x)
(if (= x 0) 1 (* x (fact fact (- x 1)))))) 5)
【讨论】:
这是一个递归函数,使用 lambda 计算 5 的阶乘
((lambda (f x)
(if (= x 0)
1
(* x (f f (- x 1)))))
(lambda (f x)
(if (= x 0)
1
(* x (f f (- x 1)))))
5)
当你在 Drracket 中运行这个程序时,你会得到 120 :)
【讨论】: