F# 正确使用序列缓存

发布于 2024-07-26 12:52:04 字数 386 浏览 2 评论 0原文

我正在尝试将 Seq.cache 与我制作的函数一起使用,该函数返回最多为 N 的素数序列(不包括数字 1)。我无法弄清楚如何将缓存的序列保留在范围内,但仍然使用它在我的定义中。

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 使其更快的任何想法? 目前它不断从范围中下降,并且只会降低性能。

I'm trying to use Seq.cache with a function that I made that returns a sequence of primes up to a number N excluding the number 1. I'm having trouble figuring out how to keep the cached sequence in scope but still use it in my definition.

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

Any ideas of how I could use Seq.cache to make this faster? Currently it keeps dropping from scope and is only slowing down performance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

静若繁花 2024-08-02 12:52:05

我想出了如何用折叠解决我的问题,但不是我使用 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]

I figured out how to solve my problem with a fold but not my idea of using 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]
蒲公英的约定 2024-08-02 12:52:05

你看过 LazyList 吗? 似乎它是为了解决同样的问题而设计的。 它位于 PowerPack 中。

Have you taken a look at LazyList? Seems like it's designed to solve the same problem. It's in PowerPack.

逐鹿 2024-08-02 12:52:04

Seq.cache 缓存 IEnumerable 实例,以便序列中的每个项目仅计算一次。 不过,就您而言,您正在缓存函数返回的序列,每次调用该函数时,您都会获得一个新的缓存序列,这对您没有任何好处。 正如您所概述的那样,我认为缓存并不是真正解决您的问题的正确方法; 相反,你可能应该研究一下记忆​​。

如果您想要定义一个无限可枚举的素数序列,而不是定义一个给出小于 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

我还没有比较这种方法与你的方法的性能。

Seq.cache caches an IEnumerable<T> instance so that each item in the sequence is only calculated once. In your case, though, you're caching the sequence returned by a function, and each time you call the function you get a new cached sequence, which doesn't do you any good. I don't think caching is really the right approach to your problem as you've outlined it; instead you should probably look into memoization.

If instead of defining a function giving the primes less than n you want to define an infinite enumerable sequence of primes, then caching makes more sense. That would look more like this:

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

I haven't compared the performance of this method compared to yours.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文