Haskell生成适当的随机数,无需显式递归

Haskell生成适当的随机数,无需显式递归,haskell,Haskell,这里我有一个函数来生成一个0到999之间的随机数流 randomHelp :: RandomGen g => g -> [Int] randomHelp g = zipWith (mod) (map fst $ iterate (next . snd) $ next $ snd $ split g) $ repeat 1000 我想从上面定义的流中选择所有数字,并且每个elem(I)和elem(I+1)必须尊重适当性。例如,他们的gcd必须是1。我所能想到的就是一个fold函数,因

这里我有一个函数来生成一个0到999之间的随机数流

randomHelp :: RandomGen g => g -> [Int]
randomHelp g = zipWith (mod) (map fst $ iterate (next . snd) $ next $ snd $ split g) $ repeat 1000
我想从上面定义的流中选择所有数字,并且每个
elem(I)
elem(I+1)
必须尊重适当性。例如,他们的gcd必须是1。我所能想到的就是一个fold函数,因为我可以从和累加器开始,累加器包含数字1(假设1是我想显示的第一个元素),然后我检查fold函数的适当性,如果它得到尊重,我会将元素添加到累加器中,但问题是程序阻塞,因为我认为堆栈溢出

以下是函数:

randomFunc :: RandomGen g => g -> [Int]
randomFunc g = foldl (\acc x -> if (gcd x (last acc) == 1) then acc ++ [x] else acc) [1] (randomHelp g)

注意:我不想使用显式递归。

右折叠可能更合适,例如:

import System.Random (RandomGen, randomRs, mkStdGen)

randomFunc :: RandomGen g => g -> [Int]
randomFunc g = foldr go (const []) (randomRs (1, 20) g) 1
    where go x f lst = if gcd x lst == 1 then x: f x else f lst
然后


这样做时,您可以使用
而不是
++
来构建列表,这可能会导致二次性能成本,并且您可以绕过对
last

的调用。我真的不明白这是如何工作的?你能解释一下吗?@zaig这是
foldr::Foldable t=>(a->b->b->ta->b
的一个应用程序,其中
b
本身就是一个函数,就像
c->d
,所以签名应该是
(a->(c->d)->(c->d)->(c->d)->ta->c->d
。如果你遵循签名应该理解它是如何工作的,我仍然不明白谁是函数f?按照顺序,我会说当调用go时它将是
randomRs
,但是
randomRs
需要一个生成器,而
lst
x
不是生成器。我还是有点困惑。我遗漏了什么?@zaig
(randomRs(1,20)g)
是一个无限列表,它已经传入生成器
g
。您可以用任意列表替换
(randomRs(1,20)g)
,比如
[2,3,6,8,5]
,看看这是如何工作的如果您能用列表
[2,3,6]
一步一步地解释代码,我将不胜感激。调用
go
函数时,我不知道
f
是谁。以及
go
采用的参数。
\> take 20 . randomFunc $ mkStdGen 1
[16,7,6,19,8,15,16,1,9,2,15,17,14,3,11,17,15,8,1,5]