【问题标题】:F# using sequence cache correctlyF# 正确使用序列缓存
【发布时间】:2010-11-06 19:49:48
【问题描述】:

我正在尝试将 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 来加快速度的任何想法?目前它一直在范围内下降,只会降低性能。

【问题讨论】:

    标签: caching f# sequence primes


    【解决方案1】:

    Seq.cache 缓存一个IEnumerable&lt;T&gt; 实例,以便序列中的每个项目只计算一次。但是,在您的情况下,您正在缓存函数返回的序列,并且每次调用该函数时都会得到一个 new 缓存序列,这对您没有任何好处。正如您所概述的那样,我认为缓存并不是解决问题的正确方法;相反,您可能应该研究一下 memoization。

    如果不是定义一个给出小于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
    

    我没有将这种方法的性能与您的方法进行比较。

    【讨论】:

      【解决方案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]
      

      【讨论】:

      • 使用旧的 9 月版本折叠后性能大约提高了 3 倍。我将在今天晚些时候签入 vs2010。
      • 折叠后 VS2010 的性能提高了 2 倍。很高兴知道序列的性能有所提高。
      【解决方案3】:

      你看过 LazyList 吗?似乎它旨在解决同样的问题。它在 PowerPack 中。

      【讨论】:

        猜你喜欢
        • 2011-10-06
        • 2013-11-20
        • 2013-12-29
        • 1970-01-01
        • 2011-04-16
        • 2016-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多