让我们在尾递归中作为goto指令工作?

时间:2014-11-03 00:12:43

标签: recursion scheme

我在Scheme中找到了以下Binary Search的实现:

(define (binary-search value vector)
  (let helper ((low 0)
               (high (- (vector-length vector) 1)))
    (if (< high low)
        #f
        (let ((middle (quotient (+ low high) 2)))
          (cond ((> (vector-ref vector middle) value)
                 (helper low (- middle 1)))
                ((< (vector-ref vector middle) value)
                 (helper (+ middle 1) high))
                (else middle))))))

根据评论中的内容,上面的函数使用tail-recursion来调用help函数。我想知道这是否像GOTO指令一样,因为我没有看到有一个正确的&#34;递归&#34;调用二进制搜索功能。

在这种情况下,可以说它像goto指令一样工作吗?

2 个答案:

答案 0 :(得分:2)

您所看到的内容称为let。 (如果你有点好奇的话,我写了blog post about how named let works。)你所拥有的代码完全相同:

(define (binary-search value vector)
  (define (helper low high)
    (if (< high low)
        #f
        (let ((middle (quotient (+ low high) 2)))
          (cond ((> (vector-ref vector middle) value)
                 (helper low (- middle 1)))
                ((< (vector-ref vector middle) value)
                 (helper (+ middle 1) high))
                (else middle)))))
  (helper 0 (- (vector-length vector) 1)))

换句话说, helper而不是binary-search上进行尾递归。但尾递归正在发生。

有些人会想到像goto这样的尾递归,但我不认为这是一个有用的比较。两者之间唯一的共同点是你可以使用尾递归实现循环,就像使用goto一样。但是相似之处到此为止:尾递归是一种特殊的递归(其中当前的调用帧被尾调用替换),但它仍然是递归; goto跳转到代码中的任意一点,但它是一个完全必要的操作,与递归无关。

答案 1 :(得分:0)

让我们只是lambdas的语法糖。例如:

(let ((i 2)
      (j 5)
  (* i j))

相当于

((lambda (i j) (* i j)) 2 5)

代码中的let称为let,因为您为它提供了标签。所以基本上,你伪装的lambda绑定了一个名字。从这个意义上说,它是一个转到。但是,您需要在let的范围内才能“跳转”到它。该函数是尾递归的,因为您没有推迟任何计算。在任何时间点,您只需要i和j的当前值就可以继续计算。