2017-10-20 6 views
1

この関数は約2000ステップ以上のスタックオーバーフローを引き起こします。メモリを少なくするために簡単に最適化できる方法はありますか?Lisp再帰的ランダムウォークを最適化する

(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)))) 
      ) 
     ) 
    ) 
) 
+1

より良いコード書式と再現可能なテストケースを使用して、質問を改善することができます。このStackoverflowのヘルプを参照してください: –

+0

ライナーは言うように、あなたのコードのフォーマットは非常に悪いので、それが何であるかを見ることができません(テストケースの欠如も役に立たない)しかし、この関数をコンパイルする大部分の実装では(しかし、言語で保証されていない*)、スタックを消費しないプロセスになるはずです。 (一部の実装ではコンパイルのステップが必要ないかもしれません) – tfb

答えて

2

あなただけあなたが簡単にすべての再帰的ではないし、それを書き換えることができることを意味し、尾の位置に呼び出すように見えます:私は私が持っているあなたが使用する関数を持っていないので

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

ベースケース以外でテストすることはできませんでした。

+0

私はそれを純粋に機能的に保つことを望んでいましたが、これは機能します!私はgnu clispに悩まされています。私ができる限り、メモリの制限を増やしたり、clisp do tail recursionの最適化を行う方法はありません。 –

+0

@RossGriebenow私はClispにテールコールの最適化があると思うので、関数をコンパイルしてもスタックオーバーフローは発生しませんが、Common Lisp標準ではこれを実装する必要はなく、標準で最適化のヒントを考慮することさえできませんそれらはポータブルアプリケーションで使用できます。したがって、CLにおける関数型プログラミングを行う慣用的な方法は、線形更新によるものである。このようにして、インタフェースが機能的である限り、内部的に変更することは大丈夫です。 – Sylwester

+0

@RossGriebenow BTWスタックサイズを増やすことはシステムに依存しますが、CLISP FAQには再帰のための[unixとwindowsの両方でソリューションを増やす](https://clisp.sourceforge.io/impnotes/faq.html#faqstack)があります。コンパイルや書き換えができません。 – Sylwester

関連する問題