我的任务是创建一个尾递归函数,从列表中删除第n个元素,1< = n< = listlength,只有两个参数,列表x和元素n。因此,(删除1'(a b c d))将返回(b c d)。我写了以下内容,并希望得到一些保证,它确实是尾递归的。我唯一模糊的是递归调用是否可以嵌套在IF语句中。
(define (remove n x)
; if n is 1, just return the cdr
(if (and (not (list? (car x))) (= n 1))
(cdr x)
; if the car is not a list, make it one, and call recursively
(if (not (list? (car x)))
(remove (- n 1) (cons (list (car x)) (cdr x)))
; if n !=1, insert the cadr into the list at the car.
; Else, append the list at the car with the cddr
(if (not(= n 1))
(remove (- n 1) (cons (append (car x) (list(cadr x))) (cddr x)))
(append (car x) (cddr x))))))
答案 0 :(得分:2)
是的,该过程是尾递归的,这意味着:无论何时执行递归调用,它都是在该特定执行分支中发生的最后一件事,在递归返回后没有更多事情要做 - 因此,我们说递归调用位于尾部位置。
如果我们使用cond
而不是嵌套的if
重写过程,可以清楚地看到这一点,在这里您将看到每个执行分支都会导致基本案例或递归案例,并且所有递归调用都处于尾部位置:
(define (remove n x)
; base case #1
(cond ((and (not (list? (car x))) (= n 1))
; return from base case, it's not recursive
(cdr x))
; recursive case #1
((not (list? (car x)))
; recursive call is in tail position
(remove (- n 1) (cons (list (car x)) (cdr x))))
; recursive case #2
((not (= n 1))
; recursive call is in tail position
(remove (- n 1) (cons (append (car x) (list(cadr x))) (cddr x))))
; base case #2
(else
; return from base case, it's not recursive
(append (car x) (cddr x)))))
有关为什么if
特殊形式的后续/替代部分可以被认为是尾递归的更为技术性的解释,请查看修订后的^ 7报告的当前草案的第3.5节。语言方案 - 语言规范,这里是pdf文件的link(实质上相同的考虑因素适用于R5RS,只是它们在R7RS中有更详细的解释)。特别是:
如果以下表达式之一位于尾部上下文中,则显示为⟨tail表达式的子表达式位于尾部上下文中
...
(if ⟨expression⟩ ⟨tail expression⟩ ⟨tail expression⟩)
(if ⟨expression⟩ ⟨tail expression⟩)
答案 1 :(得分:0)
这是关于句法形式的尾递归位置的Scheme规范: