Haskell中定义范围内的随机双精度列表?

Arn*_*hor 6 random haskell

如何列出符合定义范围的"Double"类型的随机数?关于像我这样的新手的这个问题的信息有点令人困惑.尝试类似的东西:

randomlist :: Int -> Int -> [IO Double]
randomlist a b = do
  g <- newStdGen
  return (randomRs (a,b) g)
Run Code Online (Sandbox Code Playgroud)

失败,错误:

Couldn't match expected type `[t0]' with actual type `IO StdGen'
Run Code Online (Sandbox Code Playgroud)

你能指出我的代码中的错误吗?

ham*_*mar 7

主要的错误在于你的签名.删除它并询问ghci推断类型是什么给出了这个:

*Main> :t randomlist
randomlist :: Random a => a -> a -> IO [a]
Run Code Online (Sandbox Code Playgroud)

当然,Double -> Double -> IO [Double]如果您愿意,可以将此约束为类型,fromIntegral如果要进一步限制为整数边界,可以添加一些调用:

randomlist :: Int -> Int -> IO [Double]
randomlist a b = do
    g <- newStdGen
    return (randomRs (fromIntegral a, fromIntegral b) g)
Run Code Online (Sandbox Code Playgroud)

注意类型[IO Double]和之间的区别IO [Double].前者是返回的计算列表Double,而后者是返回列表的单个计算Double,在这种情况下是您想要的.

错误消息可能有点神秘,但它基本上告诉你,因为newStdGen有类型IO StdGen,<-只有当do-expression 的类型是a时才允许绑定IO something,而你的类型签名表示类型应该是[something].


Ant*_*sky 7

你几乎拥有它.你有两个问题.主要问题是[IO Double]你的类型签名的一部分; 这表示你将返回一个IO动作列表,每个动作都可以生成一个双重动作.相反,您希望返回IO [Double]-an IO动作,该动作在运行时会生成无限的双精度列表.如果你改变它,你差不多完成了; 剩下的问题是你有ab作为Ints,但返回Doubles.如果你想返回双打,你的界限需要加倍,对于整数也是如此.(要将Ints 转换为Doubles,您可以使用fromIntegral;反之亦然,您可以使用round.)因此,为了使您的代码正常工作,您需要更改的是类型签名:

randomlist :: Double -> Double -> IO [Double]
randomlist a b = do
  g <- newStdGen
  return (randomRs (a,b) g)
Run Code Online (Sandbox Code Playgroud)

事实上,如果你没有留下类型签名,一切都会好的; GHC会推断出更一般的类型签名Random a => a -> a -> IO [a].换句话说,您的函数适用于您可以生成随机成员的任何数据类型.

您还可以稍微简化代码.例如,以下内容是等效的:

randomlist :: Random a => a -> a -> IO [a]
randomlist a b = fmap (randomRs (a,b)) newStdGen
Run Code Online (Sandbox Code Playgroud)

fmap :: Functor f => (a -> b) -> f a -> f b功能允许你申请一个普通的函数里面一个仿函数.什么是算子?粗略地说,它是某种容器; 型的功能,例如[],(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
Run Code Online (Sandbox Code Playgroud)

<$>是...的同义词fmap; 它看起来像$普通的应用程序,因为它们几乎是一样的. <$>只是让你进入一个仿函数(这里IO).


1:如果不是很清楚,不要担心; 你可以使用这些东西而不用详细了解它,这最终会导致理解.