简体   繁体   English

球拍:识别尾递归?

[英]Racket: Identifying tail recursion?

I wrote two different functions in racket to determine whether a list of numbers is ascending: 我在球拍中写了两个不同的函数来确定数字列表是否在升序:

(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))))

I had the hardest time determining whether or not the first ascending was tail recursive, so I rewrote it using what I believe to be tail recursion. 我最难确定第一次提升是否是尾递归,所以我用我认为的尾递归重写了它。

The reason why I retrospectively believe the first one to not be tail recursive is that I believe at each level of recursion, the function will be waiting for the second argument in the "and" statement to return before it can evaluate the boolean expression. 我回顾性地认为第一个不是尾递归的原因是我相信在每个递归级别,函数将等待“and”语句中的第二个参数返回,然后才能评估布尔表达式。 Conversely, for ascending-tail-helper, I am able to evaluate the lesser than expression before I do my recursive call. 相反,对于升序尾助手,我能够在进行递归调用之前评估小于表达式。

Is this correct, or did I make myself even more confused than before? 这是正确的,还是让自己比以前更加困惑?

DrRacket can help you determine whether a call is in tail position or not. DrRacket可以帮助您确定呼叫是否处于尾部位置。 Click the "Syntax Check" button. 单击“语法检查”按钮。 Then move the mouse pointer to the left parenthesis of the expression in question. 然后将鼠标指针移动到相关表达式的左括号。 In your example I get this: 在你的例子中,我得到了这个:

在此输入图像描述

The purple arrow shows that the expression is in tail-position. 紫色箭头表示表达式处于尾部位置。

From the manual: 从手册:

Tail Calls: Any sub-expression that is (syntactically) in tail-position with respect to its enclosing context is annotated by drawing a light purple arrow from the tail expression to its surrounding expression. 尾调用:通过从尾表达式到其周围表达式绘制浅紫色箭头来注释(语法上)相对于其封闭上下文在尾部位置的任何子表达式。

You are correct, in the first version the recursive call returns to and , whereas in the second version the recursive call is a tail call. 你是正确的,在第一个版本的递归调用返回and ,而在第二个版本的递归调用是一个尾调用。

However, and is a macro, and is generally expanded using if 但是, and是一个宏,并且通常使用if扩展

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

which is tail recursive. 这是尾递归。

One of the requirements for a function to be in tail position is that it's return value be usable as the return value of the parent function without modification or inspection. 函数处于尾部位置的要求之一是它的返回值可用作父函数的返回值而无需修改或检查。 That is, the parent function should be able to return immediately, having evaluated the tail position statement. 也就是说,在评估尾部位置语句之后,父函数应该能够立即返回。

On first appearance, your first function,inspects the return value of ascending . 在第一次出现时,您的第一个功能,检查升序的返回值。 It seems that doesn't return ascending 's value but, instead, a value derived from it. 似乎不会返回提升的价值,而是从它中获得的价值。 However , according to the relevant section of the R5RS spec, the final expression in an and statement is in tail position. 然而 ,根据该规范R5RS的相关部分,在一个最终表达式语句在尾部位置。 (When I'm properly awake, I know this) (当我清醒的时候,我知道这一点)

So you are wrong. 所以你错了。

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

(Note: edited to correct my initial hasty answer). (注意:编辑以纠正我最初仓促的答案)。

Racket's documentation on tail positions says that the place to check what's in tail position and what's not is the documentation for the particular form: 关于尾部位置的 Racket 文档说明了检查尾部位置和不匹配的位置是特定形式的文档:

Tail-position specifications provide a guarantee about the asymptotic space consumption of a computation. 尾部位置规范提供了关于计算的渐近空间消耗的保证。 In general, the specification of tail positions goes with each syntactic form, like if . 一般来说,尾部位置的规范与每种句法形式一致, if

Racket's docs on and say (emphasis added): Racket的文档说(重点补充):

 (and expr ...) 

If no exprs are provided, then result is #t. 如果没有提供exprs,则结果为#t。

If a single expr is provided, then it is in tail position , so the results of the and expression are the results of the expr. 如果提供了单个expr,那么它处于尾部位置 ,因此和表达式的结果是expr的结果。

Otherwise, the first expr is evaluated. 否则,将评估第一个expr。 If it produces #f, the result of the and expression is #f. 如果它产生#f,则表达式的结果为#f。 Otherwise, the result is the same as an and expression with the remaining exprs in tail position with respect to the original and form. 否则,结果与a和表达式相同,其中尾部位置的剩余exprs相对于原始和形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM