Recursion 在函数中包含累加器等参数的最佳实践是什么?

Recursion 在函数中包含累加器等参数的最佳实践是什么?,recursion,coding-style,lisp,Recursion,Coding Style,Lisp,最近我写了更多的Lisp代码。特别是递归函数,它获取一些数据,并构建结果数据结构。有时,除了用户提供的数据之外,我似乎还需要向函数的下一次调用传递两三条信息。让我们称之为累加器 将这些接口组织到我的代码中的最佳方式是什么 目前,我做了如下工作: (defun foo (user1 user2 &optional acc1 acc2 acc3) ;; do something (foo user1 user2 (cons x acc1) (cons y acc2) (con

最近我写了更多的Lisp代码。特别是递归函数,它获取一些数据,并构建结果数据结构。有时,除了用户提供的数据之外,我似乎还需要向函数的下一次调用传递两三条信息。让我们称之为累加器

将这些接口组织到我的代码中的最佳方式是什么

目前,我做了如下工作:

(defun foo (user1 user2 &optional acc1 acc2 acc3)
    ;; do something
    (foo user1 user2 (cons x acc1) (cons y acc2) (cons z acc3)))
这是我希望的,但我很担心,因为我不需要向程序员提供可选参数

我正在考虑的3种方法:

  • 有一个包装器函数,鼓励用户使用该函数立即调用扩展定义

  • 在签名简洁的函数内部使用
    标签

  • 只需开始使用循环和变量。然而,我不希望这样,因为我真的很喜欢递归


谢谢大家

我认为,你对用户屏蔽实施细节的冲动是明智的。我不知道CommonLisp,但在Scheme中,您可以通过在公共函数的词法范围中定义helper函数来实现

(define (fibonacci n)
  (let fib-accum ((a 0)
                  (b 1)
                  (n n))
    (if (< n 1)
        a
        (fib-accum b (+ a b) (- n 1)))))
(定义(斐波那契n)
(设fib累计((a0)
(b)1
(n)
(如果(

let
表达式定义一个函数并将其绑定到一个仅在let中可见的名称,然后调用该函数。

如果您想编写惯用的公共Lisp,我建议使用循环和变量进行迭代。递归很酷,但对于普通Lisper来说,它只是众多工具中的一种。此外,通用Lisp规范不能保证尾部调用消除


也就是说,如果你有一个结构,比如一个树,它不可避免地是递归的,并且你无论如何都不能得到尾部调用,我建议你使用
标签
方法。可选参数让您的实现细节泄露给调用者。

我已经使用了您提到的所有选项。它们都有各自的优点,所以归根结底是个人喜好


我已经开始使用我认为合适的任何东西。如果我认为在API中保留
&可选的
累加器可能对用户有意义,那么我将它保留在API中。例如,在类
reduce
功能中,用户可以使用累加器提供起始值。否则,我通常会将其重写为
循环
执行
、或
iter
(来自迭代库)形式,如果这样理解有意义的话。有时,也会使用
标签
帮助程序。

是的,我认为在这种情况下,Common Lisp的
标签
与Scheme的
let
相当。谢谢。我有一些处理树的函数,所以我将它们转换为使用
标签
。另一组函数只在列表上运行,因此我利用这个机会熟悉了
循环