我是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
但我不知道如何将其转换为懒惰序列。
答案 0 :(得分:7)
请参阅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 Problem 3问题,方法是实现一个特定的数字因子,而不是将数字穷尽地用素数除以最大值。虽然你最终还是需要一个素数序列生成器来解决问题。
答案 1 :(得分:3)
如果您想模仿Haskell的懒惰,可以使用FSharp.PowerPack.dll中的LazyList类型。 LazyList.Cons(p,xs)是对应于Haskell中的p:xs的模式匹配。 consDelayed中的'延迟'是必要的,因为常规的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]
答案 2 :(得分: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