私はF#コアライブラリソース(v.2.0)を読んでいて、かなり興味深いものを見つけました。それは、非常に単純なものとは
List.foldBack
異なり、可変配列を介して実装されています。ここにソースがあります、またはあなたはここList.fold
でそれを見つけるかもしれません:
let foldArraySubRight (f:OptimizedClosures.FSharpFunc<'T,_,_>) (arr: 'T[]) start fin acc =
let mutable state = acc
for i = fin downto start do
state <- f.Invoke(arr.[i], state)
state
// this version doesn't causes stack overflow - it uses a private stack
let foldBack<'T,'State> f (list:'T list) (acc:'State) =
// skipped optimized implementations for known lists
// It is faster to allocate and iterate an array than to create all those
// highly nested stacks. It also means we won't get stack overflows here.
let arr = toArray list
let arrn = arr.Length
foldArraySubRight f arr 0 (arrn - 1) acc
継続を使用しない理由は何ですか?
以下のコードのような素朴なものは、高度に最適化されたライブラリメソッドよりも2〜3倍遅く動作するようです。本当に「配列の割り当てと反復が高速」であるかどうかは疑わしいようです。また、末尾再帰であるため、ここではStackOverflowはありません。
私は何かが足りないのですか?
let foldBack2 predicate acc list =
let rec loop list cont =
match list with
| [] -> cont acc
| h::t -> loop t (fun racc -> cont (predicate h racc))
loop list id