发布的代码不起作用;但即使经过修复以使其确实工作,这也不是一个惯用的 Scheme 解决方案。
要使发布的代码工作:
-
nil 必须替换为'(),因为Scheme 不代表nil 的空列表
-
square 必须在 car 的 items-remaining 上调用
-
set! 应该通过添加平方数来修改result,而不是尝试添加递归调用的结果。这在这里根本不起作用,因为set! 返回未指定的值;但即使它确实工作,这也不会是尾递归(即,这不会是一个迭代过程)
-
result 的值必须返回,因为result 确实是一个累加器,所以必须先将其反转
这是一个修正版:
(define (square-list-0 items)
(define result '()) ; set result
(define (iter items-remaining)
(cond ((null? items-remaining)
result)
(else
(set! result (cons (square (car items-remaining))
result))
(iter (cdr items-remaining)))))
(iter items)
(reverse result))
更好的解决方案不会使用突变,也不需要(define result '()):
(define (square-list-1 xs)
(define (iter xs acc)
(if (null? xs)
(reverse acc)
(iter (cdr xs) (cons (square (car xs)) acc))))
(iter xs '()))
这里将一个累加器acc 添加到iter 过程的lambda 列表中。在计算结果时,它们被转换为acc,这意味着在此过程结束时,acc 中的第一个数字基于xs 中的最后一个数字。所以,累加器在返回之前是反转的。
另一种方法,可能是更惯用的解决方案,是使用一个名为let的:
(define (square-list-2 xs)
(let iter ((xs xs)
(acc '()))
(if (null? xs)
(reverse acc)
(iter (cdr xs) (cons (square (car xs)) acc)))))
这更简洁一些,它允许您在 iter 过程定义的开头将参数绑定到它们的参数。
上述所有三个解决方案都定义了迭代过程,并且所有三个都给出了相同的结果:
> (square-list-0 '(1 2 3 4 5))
(1 4 9 16 25)
> (square-list-1 '(1 2 3 4 5))
(1 4 9 16 25)
> (square-list-2 '(1 2 3 4 5))
(1 4 9 16 25)
当然,你可以使用map:
> (map square '(1 2 3 4 5))
(1 4 9 16 25)