我有一個F#函數,它返回跳轉n的模式中從0開始的數字列表,選擇n,跳過n,選擇n ...直到限制。例如,輸入2的這個函數將返回[2, 3, 6, 7, 10, 11...]
。F中的緩慢遞歸遞歸#
最初我實現此作爲如下面的非尾遞歸函數:
let rec indicesForStep start blockSize maxSize =
match start with
| i when i > maxSize -> []
| _ -> [for j in start .. ((min (start + blockSize) maxSize) - 1) -> j] @ indicesForStep (start + 2 * blockSize) blockSize maxSize
以爲尾遞歸是可取的,我重新實現它使用的蓄能器列表如下:
let indicesForStepTail start blockSize maxSize =
let rec indicesForStepInternal istart accumList =
match istart with
| i when i > maxSize -> accumList
| _ -> indicesForStepInternal (istart + 2 * blockSize) (accumList @ [for j in istart .. ((min (istart + blockSize) maxSize) - 1) -> j])
indicesForStepInternal start []
然而,當我在單聲道下用參數1,1和20,000(即應該返回[1, 3, 5, 7...]
高達20,000)時,在fsi下運行它時,尾遞歸版本明顯比第一版本慢(12秒與亞秒相比)。
爲什麼尾遞歸版本較慢?是因爲列表串聯?它是一個編譯器優化?我有沒有實現它尾遞歸?
我也覺得好像我應該使用高階函數來做到這一點,但我不確定如何去做。
不幸的是,我沒有時間來提供替代的代碼,但幾個簡單的觀察:1)它是尾遞歸,2)名單追加爲O(N),因此效率低下。我建議反轉(下移)你的列表理解,把它歸結爲accumList,並在你返回第一個模式匹配之前反轉accumList。 – Daniel 2011-03-28 14:37:52
非常感謝大家;這些答案非常有幫助,信息量大,教育程度也很高。 – Gnat 2011-03-29 14:20:06