在Haskell中使用随机数显示整数运算时出现问题

dev*_*ium 2 random haskell functional-programming

假设我想在Haskell中生成一个随机数.为此,我会利用

randomRIO (0, 10)
Run Code Online (Sandbox Code Playgroud)

为我生成0到10之间的数字.它的类型是

randomRIO (0,10) :: (Random a, Num a) => IO a
Run Code Online (Sandbox Code Playgroud)

现在,假设我将其结果赋值给一个值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
Run Code Online (Sandbox Code Playgroud)

当尝试询问Ghci时,问题也会发生

[randomRIO (0, 10) | x <- [0..10]]
Run Code Online (Sandbox Code Playgroud)

错误信息有点神秘,如何在Haskell中使用随机数?

ham*_*mar 10

type的IO Integer值不是整数.这是一个动作,当执行时,将返回一个整数.区别很重要.执行IO操作的唯一方法是将它们连接起来main,或者将它们键入GHCi.

randomRIO (0, 10)是一个动作,当执行时,在0和之间返回一个随机数10.请注意,这不是一个函数,因为函数必须始终在给定相同输入的情况下返回相同的结果,尽管我们有时将其称为不纯函数.

所以问题是,你如何采取一个返回整数的动作并使一个动作返回整数加2?简单,您可以使用fmap组合动作和纯函数将其结果转换为新动作.

fmap (+2) $ randomRIO (0, 10)
Run Code Online (Sandbox Code Playgroud)

Control.Monad包含许多有用的功能,用于从其他操作中构建新操作.对于您的第二个示例,我们可以使用replicateM,它创建一个操作,在执行时,多次运行原始操作,将结果收集到列表中:

replicateM 10 $ randomRIO (0, 10)
Run Code Online (Sandbox Code Playgroud)

您还可以使用do-notation 手动获取类似结果.

有关更多信息,您应该阅读monad,例如在Learn You a Haskell中.