Haskell生成适当的随机数,无需显式递归
这里我有一个函数来生成一个0到999之间的随机数流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函数,因
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]