假设我想在Haskell中生成一个随机数。为此,我将使用
randomRIO (0, 10)
为我生成0到10之间的数字。它的类型是
randomRIO (0,10) :: (Random a, Num a) => IO a
现在,假设我将结果分配给值k
。它的类型是IO Integer
。
尝试执行k + 2
等通常的算术运算会在Ghci中产生以下结果:
<interactive>:1:3:
No instance for (Num (IO Integer))
arising from the literal `2'
Possible fix: add an instance declaration for (Num (IO Integer))
In the second argument of `(+)', namely `2'
In the expression: k + 2
In an equation for `it': it = k + 2
当尝试向Ghci询问
时,问题也会发生[randomRIO (0, 10) | x <- [0..10]]
错误信息有点神秘,如何在Haskell中使用随机数?
答案 0 :(得分:10)
类型IO Integer
的值不是整数。这是一个动作,当执行时,将返回一个整数。区别很重要。执行IO
操作的唯一方法是将它们连接到main
,或者将它们键入GHCi。
因此randomRIO (0, 10)
是一项操作,执行后会在0
和10
之间返回一个随机数。请注意,这是不是函数,因为函数必须始终在给定相同输入的情况下返回相同的结果,尽管我们有时将其称为不纯函数。
所以问题是,你如何采取一个返回整数的动作并使一个动作返回整数加2?很简单,您可以使用fmap
组合动作和纯函数,将其结果转换为新动作。
fmap (+2) $ randomRIO (0, 10)
Control.Monad
包含许多用于从其他操作构建新操作的有用功能。对于您的第二个示例,我们可以使用replicateM
,这会创建一个操作,在执行时,多次运行原始操作,将结果收集到列表中:
replicateM 10 $ randomRIO (0, 10)
您还可以使用do
- 表示法手动获得类似的结果。
有关详细信息,请阅读monad,例如Learn You a Haskell。
答案 1 :(得分:4)
最好通过Learn You a Haskell之类的资源来完成工作。一个非常相关的部分是here。
答案 2 :(得分:3)
由于您提到了GHCi,请注意您还可以在提示中执行IO操作,并使用<-
将操作中的值绑定到名称。
a <- randomRIO (0, 10)
a + 2
但是,我建议你阅读安东尼和哈马尔联系的教程。它将更详细地解释上述语法(以及操纵monadic值的其他方法)。