我在球拍中写了两个不同的函数来确定数字列表是否在升序:
(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))))
我最难确定第一次提升是否是尾递归,所以我用我认为是尾递归的方法重写了它 .
我回顾性地认为第一个不是尾递归的原因是我相信在每个递归级别,函数将等待“and”语句中的第二个参数返回,然后才能评估布尔表达式 . 相反,对于升序尾助手,我能够在进行递归调用之前评估小于表达式 .
这是正确的,还是让自己比以前更加困惑?
4 回答
你是对的,在第一个版本中,递归调用返回到
and
,而在第二个版本中,递归调用是尾调用 .但是,
and
是一个宏,通常使用if
进行扩展这是尾递归 .
DrRacket可以帮助您确定呼叫是否处于尾部位置 . 单击“语法检查”按钮 . 然后将鼠标指针移动到相关表达式的左括号 . 在你的例子中,我得到了这个:
紫色箭头表示表达式处于尾部位置 .
从手册:
函数在 tail position 中的一个要求是它的返回值可用作父函数的返回值而无需修改或检查 . 也就是说,在评估尾部位置语句之后,父函数应该能够立即返回 .
在第一次出现时,您的第一个函数,检查 ascending 的返回值 . 它似乎不会返回 ascending 的值,而是返回从它派生的值 . However ,根据R5RS规范的相关部分, and 语句中的最终表达式处于尾部位置 . (当我清醒的时候,我知道这一点)
所以你错了 .
http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-6.html#%_sec_3.5
(注意:编辑以纠正我最初仓促的答案) .
Racket的documentation on tail positions表示检查's in tail position and what'不是特定表格的文档的地方:
Racket's docs on and说(重点补充):