有一个众所周知的解决方案可以生成无限的汉明数流(即所有正整数n
,其中n = 2^i * 3^j * 5^k
)。我在 F# 中以两种不同的方式实现了这一点。第一种方法使用seq<int>
. 解决方案很优雅,但性能很糟糕。第二种方法使用自定义类型,其中尾部包裹在Lazy<LazyList<int>>
. 解决方案很笨拙,但性能令人惊叹。
有人可以解释为什么使用的性能seq<int>
如此糟糕以及是否有办法解决它?谢谢。
方法 1 使用seq<int>
.
// 2-way merge with deduplication
let rec (-|-) (xs: seq<int>) (ys: seq<int>) =
let x = Seq.head xs
let y = Seq.head ys
let xstl = Seq.skip 1 xs
let ystl = Seq.skip 1 ys
if x < y then seq { yield x; yield! xstl -|- ys }
elif x > y then seq { yield y; yield! xs -|- ystl }
else seq { yield x; yield! xstl -|- ystl }
let rec hamming: seq<int> = seq {
yield 1
let xs = Seq.map ((*) 2) hamming
let ys = Seq.map ((*) 3) hamming
let zs = Seq.map ((*) 5) hamming
yield! xs -|- ys -|- zs
}
[<EntryPoint>]
let main argv =
Seq.iter (printf "%d, ") <| Seq.take 100 hamming
0
方法 2 使用Lazy<LazyList<int>>
.
type LazyList<'a> = Cons of 'a * Lazy<LazyList<'a>>
// Map `f` over an infinite lazy list
let rec inf_map f (Cons(x, g)) = Cons(f x, lazy(inf_map f (g.Force())))
// 2-way merge with deduplication
let rec (-|-) (Cons(x, f) as xs) (Cons(y, g) as ys) =
if x < y then Cons(x, lazy(f.Force() -|- ys))
elif x > y then Cons(y, lazy(xs -|- g.Force()))
else Cons(x, lazy(f.Force() -|- g.Force()))
let rec hamming =
Cons(1, lazy(let xs = inf_map ((*) 2) hamming
let ys = inf_map ((*) 3) hamming
let zs = inf_map ((*) 5) hamming
xs -|- ys -|- zs))
[<EntryPoint>]
let main args =
let a = ref hamming
let i = ref 0
while !i < 100 do
match !a with
| Cons (x, f) ->
printf "%d, " x
a := f.Force()
i := !i + 1
0