関数がブラック ボックスの場合、単一の反復を使用してこれを行う唯一の方法は、Seq.cache
関数 (シーケンスを 1 回評価し、結果をメモリに格納する) を使用するか、シーケンスを他のメモリ内表現に変換することです。
関数がseq<T>
引数として受け取る場合、それが一度だけ評価されるという保証さえありません。標準偏差の通常の実装では、最初に平均を計算し、次にシーケンスを再度反復してエラーの二乗を計算します。
1 回のパスで標準偏差を計算できるかどうかはわかりません。しかし、関数を で表現すればそれが可能ですfold
。たとえば、2 つのパスを使用して最大値と平均値を計算すると、次のようになります。
let maxv = Seq.fold max Int32.MinValue input
let minv = Seq.fold min Int32.MaxValue input
次のような単一のパスを使用してそれを行うことができます。
Seq.fold (fun (s1, s2) v ->
(max s1 v, min s2 v)) (Int32.MinValue, Int32.MaxValue) input
ラムダ関数は少し見にくいですが、コンビネータを定義して 2 つの関数を構成できます。
let par f g (i, j) v = (f i v, g j v)
Seq.fold (par max min) (Int32.MinValue, Int32.MaxValue) input
このアプローチは、 を使用して定義できる関数に対して機能しますfold
。つまり、初期値 (Int32.MinValue
最初の例) と、次の値を取得したときに初期 (前の) 状態を更新するために使用される関数 (そして、おそらく結果の後処理)。一般に、このスタイルでシングルパス関数を書き直すことができるはずですが、これが標準偏差でできるかどうかはわかりません。それは間違いなく平均的に行うことができます:
let (count, sum) = Seq.fold (fun (count, sum) v ->
(count + 1.0, sum + v)) (0.0, 0.0) input
let mean = sum / count