【问题标题】:Optimize Lisp recursive random walk优化 Lisp 递归随机游走
【发布时间】:2017-10-20 20:01:16
【问题描述】:

这个函数导致堆栈溢出大约 2000 多步,有什么方法可以轻松优化它以使用更少的内存?

(defun randomwalk (steps state)
(displaystate state)
(if (equal steps 0) nil
        (if (solved? state) t
            (let ((nrmlstate (normalize state)))
                (randomwalk (- steps 1) (applymove nrmlstate (nth (random 
(length (getallmoves nrmlstate))) (getallmoves nrmlstate))))
            )
        )
    )
)

【问题讨论】:

  • 您可能希望通过更好的代码格式和可重现的测试用例来改进您的问题。请参阅此 Stackoverflow 帮助:stackoverflow.com/help/mcve
  • 正如 Rainer 所说,代码的格式非常糟糕,以至于很难看出它做了什么(而且缺少测试用例也无济于事),但在大多数实现中(但 not 由语言保证)编译这个函数应该会导致一个不消耗堆栈的进程。 (有些实现甚至可能不需要编译步骤。)

标签: recursion optimization lisp clisp


【解决方案1】:

看起来您只在尾部位置调用,这意味着您可以轻松地将其重写为根本不递归:

(defun randomwalk (steps state)
  (loop :if (= steps 0)     
            :do (return nil)
        :if (solved? state) 
            :do (return t)
        :else
            :do (let* ((nrmlstate (normalize state))
                       (moves (getallmoves nrmlstate))
                       (random-move (nth (random (length moves)) moves)))
                  (setf state (applymove nrmlstate random-move))
                  (decf steps))))

由于我没有您使用的功能,除了基本情况外,我无法对其进行测试。

【讨论】:

  • 我希望保持它纯粹的功能性,但这有效!我被 gnu clisp 困住了,就我而言,没有办法增加内存限制或让 clisp 进行尾递归优化。
  • @RossGriebenow 我认为 Clisp 具有尾调用优化,因此如果您编译该函数,您将不再出现堆栈溢出,但是由于 Common Lisp 标准不需要实现来执行此操作,甚至考虑任何优化提示在标准中,您不能在便携式应用程序中依赖它们。因此,在 CL 中进行函数式编程的惯用方法是线性更新。这样,只要接口正常,就可以在内部进行变异。
  • @RossGriebenow BTW 增加堆栈大小取决于系统,但 CLISP 常见问题解答中有 stack increasing solutions for both unix and windows 用于无法编译或重写的递归。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 2021-07-29
  • 2015-06-16
  • 1970-01-01
相关资源
最近更新 更多