如何制作符合定义范围的“Double”类型的随机数列表?对于像我这样的新手来说,关于这个问题的信息有点令人困惑。尝试类似的事情:
randomlist :: Int -> Int -> [IO Double]
randomlist a b = do
g <- newStdGen
return (randomRs (a,b) g)
失败,错误:
Couldn't match expected type `[t0]' with actual type `IO StdGen'
你能指出我的代码中的错误吗?
最佳答案
你几乎已经拥有它了。你有两个问题。主要问题是[IO Double]
您的类型签名的一部分;这表示您将返回一个 IO 操作列表,每个操作都可以产生一个 double 值。相反,您想要返回 IO [Double]
——一个 IO 操作,运行时会生成无限的 double 列表。如果你只是改变它,你就差不多完成了;剩下的问题是你有 a
和b
如Int
s,但返回 Double
s。如果你想返回 double ,你的界限必须是 double ,对于整数也是如此。 (要将 Int
s 转换为 Double
s,您可以使用 fromIntegral
;相反,您可以使用 round
。)因此,为了让您的代码正常工作,您需要更改的只是类型签名:
randomlist :: Double -> Double -> IO [Double]
randomlist a b = do
g <- newStdGen
return (randomRs (a,b) g)
事实上,如果您省略类型签名,一切都会好起来的; GHC 会推断出更通用的类型签名 Random a => a -> a -> IO [a]
。换句话说,您的函数适用于您可以生成随机成员的任何数据类型。
您还可以稍微简化您的代码。例如,以下内容是等效的:
randomlist :: Random a => a -> a -> IO [a]
randomlist a b = fmap (randomRs (a,b)) newStdGen
fmap :: Functor f => (a -> b) -> f a -> f b
function 允许您在仿函数内应用普通函数。什么是仿函数?粗略地说,它是某种容器;输入函数,例如 []
, (r ->)
,和IO
是示例。1 这正是您想要的; randomRs (a,b)
类型为(Random a, RandomGen g) => g -> [a]
,而您需要给它类型 IO StdGen
的东西,得到 Random a => IO [a]
返回。
还有一种方法可以让这个变得更好(这就是我写的方式)。如果您导入Control.Applicative
,你最终会得到
import Control.Applicative
randomlist :: Random a => a -> a -> IO [a]
randomlist a b = randomRs (a,b) <$> newStdGen
<$>
是 fmap
的同义词;它看起来像 $
,普通应用程序,因为它们几乎相同。 <$>
只是将您提升为仿函数(此处为 IO
)。
1:如果这不是很清楚,请不要担心;你可以在不完全理解它的细节的情况下使用这些东西,这最终会导致理解。
关于haskell - Haskell 中定义范围内的随机 double 列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6699277/