9

私が作成した関数で Seq.cache を使用しようとしています。これは、数値 1 を除く数値 N までの素数のシーケンスを返します。キャッシュされたシーケンスをスコープ内に保持する方法を理解するのに問題がありますが、それでも使用します私の定義では。

let rec primesNot1 n = 
    {2 .. n} 
    |> Seq.filter (fun i -> 
        (primesNot1 (i / 2) |> Seq.for_all (fun o -> i % o <> 0)))
    |> Seq.append {2 .. 2}
    |> Seq.cache

Seq.cache を使用してこれを高速化する方法についてのアイデアはありますか? 現在、スコープから外れ続けており、パフォーマンスが低下しているだけです。

4

3 に答える 3

11

Seq.cacheIEnumerable<T>シーケンス内の各項目が 1 回だけ計算されるように、インスタンスをキャッシュします。ただし、あなたの場合、関数によって返されたシーケンスをキャッシュしています。関数を呼び出すたびに、新しいキャッシュされたシーケンスが取得されますが、これは何の役にも立ちません。あなたが概説したように、キャッシングが本当にあなたの問題に対する正しいアプローチだとは思いません。代わりに、おそらくメモ化を検討する必要があります。

より少ない素数を与える関数を定義する代わりに、素数nの無限の列挙可能なシーケンスを定義したい場合は、キャッシュの方が理にかなっています。それは次のようになります。

let rec upFrom i =
  seq { 
    yield i
    yield! upFrom (i+1)
  }

let rec primes =
  seq { 
    yield 2
    yield!
      upFrom 3 |>
      Seq.filter (fun p -> primes |> Seq.takeWhile (fun j -> j*j <= p) |> Seq.forall (fun j -> p % j <> 0))
  }
  |> Seq.cache

このメソッドのパフォーマンスをあなたのものと比較していません。

于 2009-06-29T21:13:40.563 に答える
2

LazyList をご覧になりましたか? 同じ問題を解決するように設計されているようです。パワーパックに入っています。

于 2009-06-30T22:43:16.010 に答える
2

フォールドで問題を解決する方法はわかりましたが、seq.cache を使用するという考えはわかりませんでした。

let primesNot1 n = 
    {2 .. n}
    |> Seq.fold (fun primes i ->
        if primes |> Seq.for_all (fun o -> i % o <> 0) then
            List.append primes [i]
        else
            primes) [2]
于 2009-06-29T21:48:27.497 に答える