再帰をかなり使用するプログラムを実装しようとしています。だから、私はスタックオーバーフローの例外を取得する前に、私はトランポリンを実装し、それが必要な場合にはサンクを使用することはいいと思った。再帰呼び出しのシグニチャが変更され続ける
私が最初にやったのは階乗であった。ここでは、コード:
callable(f) = !isempty(methods(f))
function trampoline(f, arg1, arg2)
v = f(arg1, arg2)
while callable(v)
v = v()
end
return v
end
function factorial(n, continuation)
if n == 1
continuation(1)
else
(() -> factorial(n-1, (z -> (() -> continuation(n*z)))))
end
end
function cont(x)
x
end
はまた、私は実際のところ、私は、スタックオーバーフローを防ぐことになる、かどうかをチェックするためにナイーブ階乗を実装:
function factorial_overflow(n)
if n == 1
1
else
n*factorial_overflow(n-1)
end
end
結果は以下のとおりです。
julia> factorial_overflow(140000)
ERROR: StackOverflowError:
#JITing with a small input
julia> trampoline(factorial, 10, cont)
3628800
#Testing
julia> trampoline(factorial, 140000, cont)
0
はい、私はStacksOverflowsを避けています。そして、はい、私は結果がナンセンスであることを知っています。整数がオーバーフローしていますが、ここではスタックについて気にしました。もちろん、制作版にはそれが修正されているはずです。
(私も知っていますが、私はこれらのどちらも使用しませんでした。私はトランポリンをテストしました)。
トランポリンバージョンは、初めて実行すると時間がかかり、同じ値またはそれ以下の値を計算すると時間がかかります。 私がtrampoline(factorial, 150000, cont)
をやった場合、もう一度コンパイルするでしょう。
私は階乗のために多くの異なる署名を生成していると思います。
私の質問です:これを避けることはできますか?
'v'を匿名関数に変更しようとしましたか?私はそれがジェネリック関数であるという事実がここでいくつかの問題を引き起こすと思います。 –
@ChrisRackauckasご意見ありがとうございました。私があなたに従っているかどうかわからない。無名関数の場合、 'v'をどのようにループできますか? –