如何在 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))))
我是 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))))