Functional programming 闭包树的置换输出

Functional programming 闭包树的置换输出,functional-programming,lisp,common-lisp,Functional Programming,Lisp,Common Lisp,这是一个关于如何在Lisp中实现以下内容的概念性问题(假设在我的例子中是Common Lisp,但任何方言都可以)。假设您有一个函数,该函数创建闭包,该闭包顺序迭代任意数据集合(或以其他方式返回不同的值),并在耗尽时返回nil,即 (defun make-counter (up-to) (let ((cnt 0)) (lambda () (if (< cnt up-to) (incf cnt) nil)))) CL-U

这是一个关于如何在Lisp中实现以下内容的概念性问题(假设在我的例子中是Common Lisp,但任何方言都可以)。假设您有一个函数,该函数创建闭包,该闭包顺序迭代任意数据集合(或以其他方式返回不同的值),并在耗尽时返回nil,即

(defun make-counter (up-to)
  (let ((cnt 0))
    (lambda ()
       (if (< cnt up-to)
           (incf cnt)
           nil))))

CL-USER> (defvar gen (make-counter 3))
GEN
CL-USER> (funcall gen)
1
CL-USER> (funcall gen)
2
CL-USER> (funcall gen)
3
CL-USER> (funcall gen)
NIL
CL-USER> (funcall gen)
NIL
以确保以下情况成立:

CL-USER> (defvar collection (permute-closures (list 
                                                 (make-counter 3)
                                                 (make-counter 3))))
CL-USER> (funcall collection)
(1 1)
CL-USER> (funcall collection)
(1 2)
CL-USER> (funcall collection)
(1 3)
CL-USER> (funcall collection)
(2 1)
...
等等

我最初设计它的方式是在初始计数lambda中添加一个“pause”参数,这样在迭代时,您仍然可以调用它并在传递时接收旧的缓存值:“pause t”,希望使排列稍微干净一些。此外,尽管上面的示例是两个相同闭包的简单列表,但该列表可以是任意复杂的树(可以按深度优先顺序排列,并且生成的排列集将具有树的形状)

我已经实现了这一点,但我的解决方案不是很干净,我正在尝试调查其他人会如何处理这个问题

提前谢谢



编辑感谢您提供的所有答案。我最后做的是向生成器中添加一个“continue”参数,并通过用一个排列该列表的闭包替换任何嵌套列表来扁平化我的结构。除非传递“continue”,否则生成器不会前进并始终返回最后一个缓存的值。然后我递归地调用每个生成器,直到找到最后一个cdr或一个nil。如果我到了最后一个cdr,我就撞到了。如果我得到一个零,我会撞上它前面的一个,并重置它后面的每个闭包。

我会向计数器添加以下任一项:

  • 能够将计数器复位到起始位置

  • 计数完成后让计数器返回NIL,然后在下一次调用时再次从第一个值开始


    • 显然,您需要某种方法多次使用生成器返回的每个值

      除了雷纳·乔斯维格的建议外,我想到了三种方法

      缓存值
      permute闭包
      当然可以通过将每个生成器返回的每个值存储在一个列表中来记住,并反复使用这些值。这种方法显然意味着一些内存开销,如果生成的序列可能是无限的,那么它就不能很好地工作

      在每次迭代中创建新的生成器 在这种方法中,您将更改
      permute闭包的签名
      ,将其作为未准备好使用生成器的参数,而是创建生成器的thunk。您的示例如下所示:

      (permute-closures (list (lambda () (make-counter 3))
                              (lambda () (make-counter 3))))
      
      这样,
      permute闭包
      就可以通过简单地重新创建生成器来重置生成器

      使生成器状态可复制 您可以提供一种复制发电机及其状态的方法。这有点像方法2,即
      permute闭包
      将根据需要重置生成器,除非重置将通过还原到原始状态的副本来完成。此外,您还可以进行部分重置(即,回溯到任意点,而不仅仅是开始),这可能会或可能不会使
      置换闭包的代码大大简化


      在具有一级连续体(如Scheme)的语言中,复制生成器状态可能要容易一些,但如果所有生成器都遵循某个预定义的结构,用
      define generator
      宏或类似的东西将其抽象出来在Common Lisp中也应该是可能的。

      这是一个答案还是一个注释?@Vijay Mathew:他有一个“概念问题”,我用“概念答案”回答了我首先要做什么来解决这个问题。特别是因为这听起来像是一个家庭作业问题,而且这个问题只发布了一个实现的解决方案的小草图。介意发布您当前的解决方案吗?谢谢,我会将这个标记为已接受。我编辑了我原来的帖子来解释我最终做了什么。
      (permute-closures (list (lambda () (make-counter 3))
                              (lambda () (make-counter 3))))