如何在CHICKEN中实现可选参数?

时间:2019-06-11 20:41:20

标签: recursion scheme tail-recursion optional-arguments chicken-scheme

我是第一次接触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中吗?

2 个答案:

答案 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))))