如何通过尾递归检查Scheme中的数字是否为2的幂?

时间:2011-06-26 21:40:28

标签: scheme

(define (ispowerof2? n)
  (cond ((< n 1) #f)
    ((= n 1) #t)
    ((> (remainder n 2) 0) #f)
    (else (ispowerof2? (/ n 2)))))

此代码是否正确以及如何使用尾递归编写相同的函数?

3 个答案:

答案 0 :(得分:1)

不完全。这一行:

(else (ispower2? (/ n 2)))))

包含错误 - 应为ispowerof2。否则,这是尾递归。

答案 1 :(得分:1)

我同意其他两个答案。更深入地解释一下:“尾递归”函数是所有递归调用都处于尾部位置的函数。这引出了什么构成尾调用的问题。

查看尾调用的一种方法是使用DrRacket的步进器运行此函数。特别是,将语言级别设置为“Beginning Student”并单击此程序上的“step”按钮:

(define (ispowerof2? n)
  (cond
   ((< n 1) false)
   ((= n 1) true)
   ((> (remainder n 2) 0) false)
   (else (ispowerof2? (/ n 2)))))

(ispowerof2? 36)

...然后前进,直到你进行递归呼叫:

(define (ispowerof2? n)
  (cond
   ((< n 1) false)
   ((= n 1) true)
   ((> (remainder n 2) 0) false)
    (else (ispowerof2? (/ n 2)))))

(ispowerof2? (/ 36 2)) 

请注意,递归调用位于顶层;没有“上下文”包装它,代码将应用于调用的结果。这就是“尾调”的意思。将此与计算列表长度的函数进行对比:

(define (len l)
  (cond
   ((empty? l) 0)
   (else (+ 1 (len (rest l))))))

(len (cons 3 (cons 4 empty))

前进直到你收到递归电话,你会看到:

(define (len l)
  (cond
   ((empty? l) 0)
   (else (+ 1 (len (rest l))))))

(+ 1 (len (list 4)))

查看对'len'的递归调用是如何在(+ 1 ...)表达式中进行的?那是因为这个电话不在尾部;在递归调用返回后,还有更多的表达式要在这个函数中进行评估。

答案 2 :(得分:0)

是的,这是尾递归的。 :)