如何将随机数用作Haskell函数中的双精度数?

如何将随机数用作Haskell函数中的双精度数?,haskell,random,types,monads,Haskell,Random,Types,Monads,我正在尝试编写一个函数,它使用一个随机数作为条件来与一个列表进行比较(该列表是通过将一个函数映射到一个整数范围而创建的)。我是以交互方式来做的,如果我通过分别定义每个术语来做,它就会起作用: import System.Random.MWC (create) import Statistics.Distribution (genContVar) import Statistics.Distribution.Uniform (uniformDistr) rng <- create rd &

我正在尝试编写一个函数,它使用一个随机数作为条件来与一个列表进行比较(该列表是通过将一个函数映射到一个整数范围而创建的)。我是以交互方式来做的,如果我通过分别定义每个术语来做,它就会起作用:

import System.Random.MWC (create)
import Statistics.Distribution (genContVar)
import Statistics.Distribution.Uniform (uniformDistr)

rng <- create
rd <- (genContVar (uniformDistr 0 1)) rng

f x = takeWhile (<rd) $ fmap (*x) [1..10]
import System.Random.MWC(创建)
导入统计。分布(genContVar)
导入统计信息.Distribution.Uniform(uniformDistr)

rng当您在GHCi中计算表达式时,您已经在
IO
monad中了。这就是OP GCHi代码工作的原因

正如n.m.在评论中指出的,单子是Haskell中使用随机数(以及所有其他不确定或有效的行为)的实用方法。如果你想写Haskell代码,你迟早要知道它们是什么。不过,好消息是,要知道什么是单子并不像有些人认为的那么难

Haskell确实有单子的语法糖,形式为
do
符号。使用该函数,您可以编写如下函数:

f x = do
  rng <- create
  rd <- (genContVar (uniformDistr 0 1)) rng

  return $ takeWhile (<rd) $ fmap (*x) [1..10]
fx=do

rng获得伪随机值的“纯”方法是向每个函数添加一个新参数(当前随机种子)和一个新输出值(修改后的种子,供以下函数使用)。组合这些修改过的函数可能会让人恼火,可以使用类似单子的
State
State
-来减少所涉及的样板文件,避免模糊函数的主要逻辑。唉,看看
getContVar
的签名,它似乎与
IO
ST
密不可分(因为
PrimMonad
constratint),所以我们不能在这里使用这种技术。谢谢,@danidiaz。如果使用“纯”方法有效,我可能会像其他方法一样尝试使用它,我并没有试图避免单子,但我在组合原则上应该兼容的变量时遇到了麻烦。我不知道什么是“Haskell”,也没有“学习”它,我实际上是想从一些数学和编程结构中学习一些,这些结构在Python、朱丽亚甚至C++中很容易实现。因此,我非常感谢您能帮我整理出一个有效的示例,但请不要为您所有的“粉丝”沾沾自喜。@TwistedMersenne也许您可以看看“随机”库,您可以使用
mkStdGen
(我们使用
getStdGen
,但这是一个
IO
操作)创建一个种子。类型
StdGen
RandomGen
的一个实例
RandomGen
是一个类型类,有点像其他语言中的“接口”。然后您可以使用诸如
random
randomR
之类的函数,它们获取种子并返回随机值以及修改的种子。可以生成的类型是
Random
typeclass的实例。@danidiaz,谢谢。由于我试图将随机数与纯数学函数结合起来,所以使用randomR可能会“更容易”。在这种情况下,我需要做更多的工作,也不清楚如何更新rng状态,因为Haskell(数学上正确但令人恼火)不允许类似于
(rd,rng)=randomR(0,1)rng
,但可能使用不同变量的额外步骤允许我每次更新“全局”
rng
状态。如果你有一个有效的例子,那就太好了,但是如果它有效的话,我会尝试发布它。谢谢,这真的很有帮助。我应该记住,GCHi在
IO
中,所以当我编写一个单线性函数时,我猜我不再在
IO
领域。你能在一行中写一个我可以交互使用的
do
语法吗?既然它在一个列表上返回一个fmap值,那么它不应该是[Double]吗?我想,单子的基本原理很清楚,就像函子和应用程序一样,定义
(>>=)::(单子m)=>MA->(a->MB)->MB
说明了几乎所有需要的内容。在实践中,对于Haskell的所有类型限制,特定情况可能不那么简单。@TwistedMersenne:要将
do
表示法写成一行,您可以使用分号和(可选)大括号,而不是依赖布局规则:
do a Well,这很有效,在ghci上它与多行环境一起工作,但是,不能让它与花括号一起工作。尽管如此,它还是会再次返回一个monad,并将问题传递给下一个函数。我希望使用一元函数最终得到一个double,而不必将整个程序包装在一元结构中,但我想Haskell就是这样。也许使用纯prng更好。@TwistedMersenne“我希望[…]最终得到一个双精度,而不必将整个程序包装在一元结构中”也许这会有帮助:
f x = let rand <- (genContVar (uniformDistr 0 1) g) in takeWhile (<rand) $ fmap (*x) [1..10]

<interactive>:39:16: error:
parse error on input ‘<-’
Perhaps this statement should be within a 'do' block?
f x = do
  rng <- create
  rd <- (genContVar (uniformDistr 0 1)) rng

  return $ takeWhile (<rd) $ fmap (*x) [1..10]