我是第一次接触CHICKEN和Scheme。为了理解尾递归,我写道:
(define (recsum x) (recsum-tail x 0))
(define (recsum-tail x accum)
(if (= x 0)
accum
(recsum-tail (- x 1) (+ x accum))))
这可以达到我的预期。但是,这似乎有些重复。有一个可选的参数应该使这种方法更加整洁。所以我尝试了:
(define (recsum x . y)
(let ((accum (car y)))
(if (= x 0)
accum
(recsum (- x 1) (+ x accum)))))
但是,在CHICKEN(可能还有其他方案的实现中)中,car
不能用于()
:
Error: (car) bad argument type: ()
还有另一种方法来实现可选函数参数,特别是在CHICKEN 5中吗?
答案 0 :(得分:3)
我认为您正在寻找的是named let
,而不是可选的过程参数。这是使用(可能)可以根据需要初始化的其他参数定义帮助程序的简单方法:
(define (recsum x)
(let recsum-tail ((x x) (accum 0))
(if (= x 0)
accum
(recsum-tail (- x 1) (+ x accum)))))
当然,我们也可以使用varargs来实现它-但我认为这看起来并不优雅:
(define (recsum x . y)
(let ((accum (if (null? y) 0 (car y))))
(if (= x 0)
accum
(recsum (- x 1) (+ x accum)))))
无论哪种方式,它都能按预期工作:
(recsum 10)
=> 55
答案 1 :(得分:3)
鸡肉具有可选参数。您可以这样做:
(define (sum n #!optional (acc 0))
(if (= n 0)
acc
(sum (- n 1) (+ acc n))))
但是我会反对使用它,因为它是非标准计划。 Chicken表示他们支持SRFI-89: Optional positional and named parameters,但它似乎是较早的版本,并且需要重做鸡蛋。无论如何,重新应用它应该可以:
;;chicken-install srfi-89 # install the egg
(use srfi-89) ; imports the egg
(define (sum n (acc 0))
(if (= n 0)
acc
(sum (- n 1) (+ acc n))))
使用rest参数的想法也起作用。但是请记住,该过程随后将为每次迭代在堆上构建一个pair
:
(define (sum n . acc-lst)
(define acc
(if (null? acc-lst)
0
(car acc-lst)))
(if (= n 0)
acc
(sum (- n 1) (+ acc n))))
所有这些泄漏内部信息。有时,具有可选参数是公共合同的一部分,但在这种情况下,是避免再写几行。通常,您不希望有人通过第二个参数,而应将内部保密。更好的方法是使用命名的let
并保持公共合同不变。
(define (sum n)
(let loop ((n n) (acc 0))
(if (= n 0)
acc
(loop (- n 1) (+ acc n))))