【问题标题】:Prime number lazy sequence素数惰性序列
【发布时间】:2011-07-21 06:05:37
【问题描述】:

我是 F# 的新手,我只是想知道是否有任何方法可以在 F# 中获得素数的惰性序列。

在 Haskell 中,我使用下一个代码:

primes :: [Integer]
primes = sieve[2..]
       where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p > 0]

在 F# 中,我可以检查数字是否为素数:

let isPrime (number : bigint) =
    match number with
        | _ -> seq { bigint(2) .. bigint(Math.Sqrt(float number))}
        |> Seq.exists (fun x -> if (number % x = bigint(0)) then true else false)
        |> not

但我不知道如何将其转换为惰性序列。

【问题讨论】:

  • 你需要bigint吗?我怀疑筛子能否很快计算出不适合long 的素数。
  • 是的,我需要,因为我正在尝试解决项目 eluer #3 任务 (projecteuler.net/index.php?section=problems&id=3)。
  • 小剧透:这个数字中最大的主要因素很适合长整数。您还可以使用 I 后缀来表示 bigint:0I 而不是 bigint 0。
  • 旁注:没有理由检查number % 4 和所有下一个偶数 - 如果number % 2 == 0,则根本不会进行检查,如果不是,则可以假设number % 4 != 0 也是如此。

标签: f#


【解决方案1】:

我没有 F# powerpack 的解决方案

module Prime
    let isPrime n = 
        let bound = int (sqrt(float n))
        seq{2..bound}
        |> Seq.exists (fun x -> n % x = 0) 
        |> not
    let rec nextPrime n = 
        if isPrime (n + 1) then n + 1
        else nextPrime (n+1)
    let sequence = 
        Seq.unfold(fun n -> Some(n, nextPrime n)) 1

【讨论】:

    【解决方案2】:

    请参阅this 问题以获取许多在 F# 中给出惰性素数序列的答案。

    对于使用您的 isPrime 实现的简单解决方案(即我认为您可能有兴趣了解如何从一般的过滤器函数生成无限序列),试试这个:

    let primes =
        Seq.initInfinite (fun i -> i + 2) //need to skip 0 and 1 for isPrime
        |> Seq.map (fun i -> bigint(i))
        |> Seq.filter isPrime
    

    但是,您可能希望通过实现一个专门分解一个数字的函数而不是穷举将该数字除以质数并取最大值来以不同的方式解决 Project Euler 问题 3。尽管您最终将需要一个素数序列生成器来解决进一步的问题。

    【讨论】:

      【解决方案3】:

      如果你想模仿 Haskell 的惰性,你可以使用 FSharp.PowerPack.dll 中的 LazyList 类型。 LazyList.Cons(p,xs) 是对应于 Haskell 中 p:xs 的模式匹配。 consDelayed 中的 'Delayed' 是必要的,因为常规的 LazyList.cons 会过于急切并且需要无限长的时间(当然受限于你的耐心)。

      您可能还会发现this 的问题很有趣。这是 F# 中的另一个 Haskell 素数筛。

      这是您在 F# 中的代码(不幸的是相当难看):

      #r "FSharp.PowerPack.dll"
      
      //A lazy stream of numbers, starting from x
      let rec numsFrom x = LazyList.consDelayed x (fun () -> numsFrom (x+1I))
      
      let rec sieve = function
          | LazyList.Cons(p,xs) ->
              LazyList.consDelayed p (fun () -> 
                      xs |> LazyList.filter (fun x -> x%p <> 0I) |> sieve)
          | _ -> failwith "This can't happen with infinite lists"
      
      let primes() = sieve (numsFrom 2I)
      

      FSI 中的示例输出:

      > primes() |> Seq.take 14 |> Seq.toList;;
      Real: 00:00:00.000, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
      val it : System.Numerics.BigInteger list =
        [2I; 3I; 5I; 7I; 11I; 13I; 17I; 19I; 23I; 29I; 31I; 37I; 41I; 43I]
      

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 2011-04-05
        • 2014-11-10
        • 2016-09-19
        • 1970-01-01
        • 1970-01-01
        • 2012-03-01
        • 1970-01-01
        • 2023-02-05
        相关资源
        最近更新 更多