球拍:识别尾递归?(Racket: Identifying tail recursion?)

2019-09-24 05:27发布

我写了球拍两个不同的函数来确定号码的清单是否上升:

(define (ascending list)
  (if (<= (length list) 1)
      #t
      (and (< (car list) (car (cdr list))) (ascending (cdr list)))))

(define (ascending-tail list)
  (ascending-tail-helper #t list))

(define (ascending-tail-helper prevBool rest)
  (if (<= (length rest) 1)
      prevBool
      (ascending-tail-helper (and prevBool (< (car rest) (car (cdr rest)))) (cdr rest))))

我有困难的时候确定第一上升是否是尾递归,所以我重写它使用的是什么,我相信是尾递归。

我之所以回顾认为,第一个不是尾递归的是,我相信在递归的每一层,该功能将在“和”的语句在等待第二个参数返回,才可以评估布尔表达式。 相反,对于上升的尾辅助,我能我做我的递归调用之前评估比表达较少。

这是正确的,还是我让自己比以前更糊涂了?

Answer 1:

你是正确的,在第一个版本的递归调用返回and ,而在第二个版本的递归调用是一个尾调用。

然而, and是一个宏观的,通常采用扩张if

(define (ascending list)
  (if (<= (length list) 1)
      #t
      (if (< (car list) (car (cdr list)))
          (ascending (cdr list))
           #f)))

这是尾递归。



Answer 2:

DrRacket可以帮助您确定呼叫是否是尾部位置与否。 单击“语法检查”按钮。 然后将鼠标指针移动到所讨论的表达式的左侧括号。 在你的榜样,我得到这样的:

紫色箭头示出了表达在尾位置。

从手册:

尾调用:任何的子表达式,它是(语法)在尾位置相对于其包围上下文通过绘制从尾部表达浅紫色箭头其周围表达注解。



Answer 3:

一个用于将在尾部位置的函数的要求是,它的返回值是可用作为父功能而无需修改或检查的返回值。 也就是说,父功能应能立即返回,已经评估了尾巴立场声明。

第一次出现时,你的第一个功能,检查上升的返回值。 看来,不返回递增的价值,但是,而是从中得到的值。 然而 ,根据该规范R5RS的相关部分,在一个最终表达式语句在尾部位置。 (当我清醒正确的,我知道这一点)

那么你就错了。

http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-ZH-6.html#%_sec_3.5

(注:编辑纠正我最初的草率的答案)。



Answer 4:

球拍的尾巴上的立场文件说,地方,检查什么在尾部位置,什么不是是特定形式的文档:

尾位置规范提供了一个关于计算的渐近空间消耗的保证。 通常,尾位置的规范去与每个语法形式,像if

球拍对文档说,(强调):

 (and expr ...) 

如果没有提供exprs,那么结果是#T。

如果提供一个单一的EXPR,那么它是在尾部位置 ,所以和表达的结果是expr的结果。

否则,第一EXPR进行评估。 如果它产生#F,的和表达的结果是#F。 否则,结果是一样的一个和表达与末尾位置的剩余exprs相对于原始和形式。



文章来源: Racket: Identifying tail recursion?