我有一個深度遞歸函數,即使在大量輸入的情況下,理論上也應該可以很好地工作。問題在寫這篇文章的時候,我忘記了C#並沒有很好地完成尾部優化,如果有的話,那麼我會得到StackOverflowException
s以滿足任何複雜的輸入。該方法的基本結構是兩種大方法,每種方法都稱爲另一種方法。在C#中優化尾部調用
public object Simplify(object param) {
if (IsSimple(param))
return param;
else
return Expand(param);
}
private object Expand(object param) {
return Simplify(ProcessExpansion(param));
}
兩個IsSimple
和ProcessExpansion
具有相對固定的堆棧深度 - 唯一的問題是簡化和展開之間的遞歸。你將如何去減少堆棧深度?
我在想返回會計算結果的代表,但這看起來像是矯枉過正 - 必須有一個更簡單的方法。這是我的一個解決方案的想法(這是不是很優美,因爲我一直在想我必須做一些可怕的錯誤這裏):
public object Simplify(object param) {
object result =() => SimplifyInternal(param);
while (result is Func<object>)
result = ((Func<object>)result)();
return result;
}
private object SimplifyInternal(object param) {
if (IsSimple(param))
return param;
else
return Expand(param);
}
private object Expand(object param) {
return() => SimplifyInternal(ProcessExpansion(param));
}
所以我的兩個問題是:
- 這是什麼這種解決方案感覺可怕嗎?
- 你能想到更好的嗎?
只需注意一點,.NET 4.0 x64運行時會優化尾部調用,而x86不會。我知道,完全愚蠢。 – 2010-09-10 00:19:39
爲什麼不在F#中編程?我寧願讓編譯器優化它(語言特性),然後祈禱抖動會計算出來。 – MrDosu 2010-09-10 00:24:41
儘管我喜歡F#,但如果可以的話,我會把這個評論排在前面。建議您將整個項目切換到F#只是因爲您需要在一個點上進行尾部呼叫優化不是很有建設性。 – 2010-09-10 00:38:08