Clojure は私が Lisp の世界に足を踏み入れた最初の試みです。数値を整数乗する単純な再帰関数を試すことにしました。十分に単純です。
(defmulti pow #(compare %2 0))
(defmethod pow 0 [a n] 1)
(defmethod pow 1 [a n] (* a (pow a (dec n))))
(defmethod pow -1 [a n] (/ 1 (pow a (* -1 n))))
整数の累乗のみを渡すとうまく機能します。しかし、それを使用して十分な大きさの累乗に上げると、(予想どおり) スタック オーバーフローが発生します。
問題は、関数が終了する前に再帰がどの程度深いかを正確に知るにはどうすればよいかということです。再帰の深さを大まかに把握する 1 つの方法は、次のようにすることです。
(defn max-depth [n]
(try
(max-depth (inc n))
(catch StackOverflowError err (do
(printf "%s at %d\n" err n)
n)
)))
(Clojure は私にとって Lisp への最初の試みなので、コードを読みやすくする方法がよくわかりません。) このコードは、スタックがオーバーフローするまで無限に再帰し、その後、爆発する前に行われた再帰の回数を返します。これは、私がどれだけの深さまで行くことが許されているかの概算図を私に与えるだけです.このアプローチには多くの問題があります.
私ができるもう1つのことは、例外をキャッチして自分でスタックを巻き戻そうとすることです...しかし、例外から必要な情報を取得する方法が実際にはわかりません。http://docs.oracle.com/javase/6/docs/api/java/lang/StackOverflowError.htmlで StackOverflowError の javadoc を見ると、有望に見えるメソッドがいくつか見られますが、できる限りうまくいきませんでした。見る。
エラーがキャッチしたスタックオーバーフローである (count (.getStackTrace エラー)) を実行しようとしましたが、「状況によってはスタックフレームが省略される可能性がある」ため、結果はわずか 1024 でした。それでうまくいきませんでした。
私が考えることができる唯一の他のことは、連続して大きな指数に対して pow を実行することです.関数が他の関数を呼び出す場合、2 つの答えは同じではありません)。
Javaでそれを行う方法もわかりませんが、もしあれば、その答えもおそらく役立つでしょう。
何か案は?ありがとう、 -- スコット