List 生成无限的RandomGen列表
我想应用一个函数f,它需要一个随机发生器覆盖一个列表。我试图为我生成一个无限的RandomGen列表,如下所示。(仅仅由函数“randoms”生成的随机值是不够的,因为所需的值范围取决于f的输入。) 不幸的是,编译器告诉我,它失败了List 生成无限的RandomGen列表,list,haskell,random,infinite,List,Haskell,Random,Infinite,我想应用一个函数f,它需要一个随机发生器覆盖一个列表。我试图为我生成一个无限的RandomGen列表,如下所示。(仅仅由函数“randoms”生成的随机值是不够的,因为所需的值范围取决于f的输入。) 不幸的是,编译器告诉我,它失败了 Test.hs:13:26: Could not deduce (g1 ~ g) from the context (RandomGen g) bound by the type signature for ra
Test.hs:13:26:
Could not deduce (g1 ~ g)
from the context (RandomGen g)
bound by the type signature for
randomGens :: RandomGen g => g -> (g, g)
at Test.hs:11:14-39
or from (RandomGen g1)
bound by an expression type signature: RandomGen g1 => (Int, g1)
at Test.hs:13:19-55
`g1' is a rigid type variable bound by
an expression type signature: RandomGen g1 => (Int, g1)
at Test.hs:13:19
`g' is a rigid type variable bound by
the type signature for randomGens :: RandomGen g => g -> (g, g)
at Test.hs:11:14
In the first argument of `random', namely `gen'
In the expression: random gen :: RandomGen g => (Int, g)
In a pattern binding:
(i, gen') = random gen :: RandomGen g => (Int, g)
只是在let绑定中跳过类型注释(Int,g1)不起作用。他需要有“random”应用程序的结果类型暂时不考虑生成无限个随机生成器列表是否真的是一种方法,存在一个在
System.Random
中调用的函数,该函数可用于创建新的生成器,而不是对伪类型调用Random
,并丢弃生成的值。使用split
可以实现randomGens
如下:
import Data.List (unfoldr)
import System.Random
randomGens :: RandomGen g => g -> [g]
randomGens = unfoldr (Just . split)
{-# LANGUAGE ScopedTypeVariables #-}
randomGens :: forall g. RandomGen g => g -> [g]
randomGens gen =
let (i, gen') = (random gen) :: RandomGen g => (Int, g)
in gen : (randomGens gen')
但是,您可能应该只使用它来生成给定范围内的无限值流。暂时忽略生成无限随机生成器列表是否真的是一种方法,存在一个在
System.Random
中调用的函数,该函数可用于创建新的生成器,而不是对伪类型调用Random
,并丢弃生成的值。使用split
可以实现randomGens
如下:
import Data.List (unfoldr)
import System.Random
randomGens :: RandomGen g => g -> [g]
randomGens = unfoldr (Just . split)
{-# LANGUAGE ScopedTypeVariables #-}
randomGens :: forall g. RandomGen g => g -> [g]
randomGens gen =
let (i, gen') = (random gen) :: RandomGen g => (Int, g)
in gen : (randomGens gen')
但是,您可能应该只使用它,它在给定范围内生成无限的值流。快速回答
您可以将所需的函数定义为
randomGens :: (RandomGen g) => g -> [g]
randomGens g = let (g0,g1) = split g in g0 : randomGens g1
稍长的回答
上述方法可能不是将需要随机性的函数应用于列表的最佳方法。我可以定义一个助手函数来实现这一点
mapRandom :: (RandomGen g) => (g -> a -> b) -> g -> [a] -> (g, [b])
mapRandom _ g [] = (g, [])
mapRandom f g (a:as) = let (_,g1) = next g
in f g a : mapRandom f g1 as
然后你就可以写了
>> g <- newStdGen
>> mapRandom f g [1..5]
([False,False,True,False,True], 1839473859 293842934)
我会把它改写成
f :: (RandomGen g) => Int -> Rand g Bool
f n = do
x <- getRandom
return (x < n)
其中,配对的第一个元素是将随机函数映射到列表上的结果,最后一个元素是生成器的当前值。请注意,在定义f
时,您根本不必担心生成器-Haskell负责在幕后更新生成器并生成新的随机数。快速回答
您可以将所需的函数定义为
randomGens :: (RandomGen g) => g -> [g]
randomGens g = let (g0,g1) = split g in g0 : randomGens g1
稍长的回答
上述方法可能不是将需要随机性的函数应用于列表的最佳方法。我可以定义一个助手函数来实现这一点
mapRandom :: (RandomGen g) => (g -> a -> b) -> g -> [a] -> (g, [b])
mapRandom _ g [] = (g, [])
mapRandom f g (a:as) = let (_,g1) = next g
in f g a : mapRandom f g1 as
然后你就可以写了
>> g <- newStdGen
>> mapRandom f g [1..5]
([False,False,True,False,True], 1839473859 293842934)
我会把它改写成
f :: (RandomGen g) => Int -> Rand g Bool
f n = do
x <- getRandom
return (x < n)
其中,配对的第一个元素是将随机函数映射到列表上的结果,最后一个元素是生成器的当前值。请注意,在定义
f
时,您根本不必担心生成器—Haskell负责在幕后更新生成器并生成新的随机数。这里的主要问题—编译器无法理解等式g1
和g
(列表总是同态!)
需要使用ScopedTypeVariables
扩展,如下所示:
import Data.List (unfoldr)
import System.Random
randomGens :: RandomGen g => g -> [g]
randomGens = unfoldr (Just . split)
{-# LANGUAGE ScopedTypeVariables #-}
randomGens :: forall g. RandomGen g => g -> [g]
randomGens gen =
let (i, gen') = (random gen) :: RandomGen g => (Int, g)
in gen : (randomGens gen')
我们为所有g添加了,以指向g
的范围上下文
正如Chris Taylor提到的,此函数无效,需要计算两次随机数-第一次计算新的g
,第二次计算新的随机数
因此,使用MonadRand
在该州保存新的发电机号更好
已更新
对于简单的情况,我们可以使用zipWith
randomsMap :: (RandomGen g, Random a) => g -> (a -> b -> c) -> [b] -> [c]
randomsMap g f xs = zipWith f (randoms g) xs
这里的主要问题是编译器无法理解等式g1
和g
(列表总是同态的!)
需要使用ScopedTypeVariables
扩展,如下所示:
import Data.List (unfoldr)
import System.Random
randomGens :: RandomGen g => g -> [g]
randomGens = unfoldr (Just . split)
{-# LANGUAGE ScopedTypeVariables #-}
randomGens :: forall g. RandomGen g => g -> [g]
randomGens gen =
let (i, gen') = (random gen) :: RandomGen g => (Int, g)
in gen : (randomGens gen')
我们为所有g
添加了,以指向g
的范围上下文
正如Chris Taylor提到的,此函数无效,需要计算两次随机数-第一次计算新的g
,第二次计算新的随机数
因此,使用MonadRand
在该州保存新的发电机号更好
已更新
对于简单的情况,我们可以使用zipWith
randomsMap :: (RandomGen g, Random a) => g -> (a -> b -> c) -> [b] -> [c]
randomsMap g f xs = zipWith f (randoms g) xs
好消息!:-)事实上,我不明白编译器的问题是什么。再加上克里斯·泰勒的答案,你就得到了我问题的完美答案。:-)好消息!:-)事实上,我不明白编译器的问题是什么。再加上克里斯·泰勒的答案,你就得到了我问题的完美答案。:-)