List 生成无限的RandomGen列表

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

我想应用一个函数f,它需要一个随机发生器覆盖一个列表。我试图为我生成一个无限的RandomGen列表,如下所示。(仅仅由函数“randoms”生成的随机值是不够的,因为所需的值范围取决于f的输入。)

不幸的是,编译器告诉我,它失败了

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
好消息!:-)事实上,我不明白编译器的问题是什么。再加上克里斯·泰勒的答案,你就得到了我问题的完美答案。:-)好消息!:-)事实上,我不明白编译器的问题是什么。再加上克里斯·泰勒的答案,你就得到了我问题的完美答案。:-)