我想生成所有自然数以及它们在素数因子中的分解,直到某个阈值。
我提出了以下功能:
vGenerate :: [a] -- generator set for monoid B* (Kleene star of B)
-> (a, (a -> a -> a)) -- (identity element, generating function)
-> (a -> Bool) -- filter
-> [a] -- B* filtered
vGenerate [] (g0,_) _ = [g0]
vGenerate (e:es) (g0,g) c =
let coEs = vGenerate es (g0,g) c
coE = takeWhile (c) $ iterate (g e) g0
in concatMap (\m -> takeWhile (c) $ map (g m) coE) coEs
然后,gen生成所有自然数及其主要因子:
gen threshold =
let b = map (\x -> (x,[x])) $ takeWhile (<= threshold) primes
condition = (<= threshold) . fst
g0 = (1,[])
g = \(n,nl)(m,ml) -> ((n*m), nl ++ ml)
in vGenerate b (g0,g) condition
primes = [2,3,5,7,11,.. ] -- pseudo code
我有以下问题:
事先并不知道我们需要多少个数字。我们可以修改vGenerate,使其以一个懒惰的无限素数列表开始,并按递增顺序生成所有因子分解?挑战在于我们有一个无限的素数列表,对于每个素数,该素数的无限列表,然后必须采取所有可能的组合。列表通过增加第一个元素自然排序,因此它们可以懒得生成。
我用monoid描述了vGenerate,并打算尽可能地保持抽象,但这可能只是混淆了代码?我想稍后概括它(更多的是作为练习而不是实际使用),例如用于在某些约束内生成栅格点,也可以放在monoid上下文中,所以我认为这是一个很好的开始摆脱对问题空间的所有引用(在casu:primes中)。但我觉得过滤函数不适合抽象:生成必须按照c测试的度量单调的顺序发生,因为一旦c不满足就终止递归。有什么建议吗?
答案 0 :(得分:6)
从data-ordlist
包中查看mergeAll :: Ord a => [[a]] -> [a]
。只要序列被排序,它就会合并一个未绑定数量的无限序列,并且序列的头部是有序的。之前我曾将它用于类似的问题,例如生成2^i*3^j
形式的所有数字。
> let numbers = mergeAll [[2^i*3^j | j <- [0..]] | i <- [0..]]
> take 20 numbers
[1,2,3,4,6,8,9,12,16,18,24,27,32,36,48,54,64,72,81,96]
您应该能够扩展它以生成包含其分解的所有数字。