我正在阅读 Brain harvey 的计算机编程结构和解释。我遇到了这个问题,我不知道该怎么做。
我们如何在 Scheme 中使用 lambda 编写递归过程?
TL;DR:使用命名let
(如果您正在立即执行递归函数)或rec
(如果您正在保存递归函数以供以后执行)。
通常的方法是 with ,或者在幕后letrec
使用 a 的东西,比如 named或。这是using的一个版本:letrec
let
rec
(factorial 10)
letrec
(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)
这里也有一个简写,虽然没有使用 named 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 组合器。:-) 但是大多数实用的 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 :)