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

How to implement optional arguments in CHICKEN?

我是 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 中?

我认为您正在寻找 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

Chicken 有可选参数。你可以这样做:

(define (sum n #!optional (acc 0))
  (if (= n 0)
      acc
      (sum (- n 1) (+ acc n))))

但是我会投票反对使用它,因为它是非标准方案。鸡说他们支持SRFI-89: Optional positional and named parameters,不过好像版本比较早,蛋需要重做。无论如何,当它是 re-applied 时,这应该可以工作:

;;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))))

您使用剩余参数的想法也行得通。但是请记住,该过程随后将为每次迭代在堆上构建一个 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))))

所有这些都泄露了内部信息。有时 public 契约的一部分有一个可选参数,但在这种情况下是为了避免多写几行。通常您不希望有人传递第二个参数,您应该将内部结构保密。更好的方法是使用 named let 并保持 public 合同不变。

(define (sum n)
  (let loop ((n n) (acc 0))
    (if (= n 0)
        acc
        (loop (- n 1) (+ acc n))))