haskell - 生成随机值列表并将它们打印到 Haskell 中的标准输出

标签 haskell

我对 Haskell 还很陌生,我正在努力实现一些相对简单的事情:生成随机数列表并将它们打印到标准输出。

由于随机概念与 FP 世界中的函数纯度完全相反(即,对于相同的输入,方法应该始终返回相同的结果),因此我理解在这种情况下,System.Random Haskell 中的模块返回 IO 操作。

到目前为止,我的代码如下所示:

import System.Random

randomNumber :: (Random a) => (a, a) -> IO a
randomNumber (a,b) = randomRIO(a,b)

main :: IO ()
main = do
   points <- sequence (map (\n -> randomNumber ((-1.0), 1.0)) [1..10])
   print points

这个想法很简单:生成一个包含十个随机元素的列表(可能有更好的方法来实现这一点)。我的第一种方法是创建一个返回随机数的函数(在本例中为 randomNumber,类型为 IO a),并在映射元素列表时使用它(生成IO 操作列表,IO [a])。

根据我的理解,sequence (map (\n -> randomNumber ((-1.0), 1.0)) [1..10]) 类型是 IO [a] 但我不知道如何使用它。我怎样才能真正使用点作为 [a] 类型的某些值而不是 IO [a]

编辑:在 do“ block ”中添加打印功能会产生一些我真的不知道如何消除的错误。

Main.hs:8:40:
    No instance for (Random a0) arising from a use of ‘randomNumber’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Random Bool -- Defined in ‘System.Random’
      instance Random Foreign.C.Types.CChar -- Defined in ‘System.Random’
      instance Random Foreign.C.Types.CDouble
        -- Defined in ‘System.Random’
      ...plus 33 others
    In the expression: randomNumber ((- 1.0), 1.0)
    In the first argument of ‘map’, namely
      ‘(\ n -> randomNumber ((- 1.0), 1.0))’
    In the first argument of ‘sequence’, namely
      ‘(map (\ n -> randomNumber ((- 1.0), 1.0)) [1 .. 10])’

Main.hs:8:55:
    No instance for (Num a0) arising from a use of syntactic negation
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Num Double -- Defined in ‘GHC.Float’
      instance Num Float -- Defined in ‘GHC.Float’
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 37 others
    In the expression: (- 1.0)
    In the first argument of ‘randomNumber’, namely ‘((- 1.0), 1.0)’
    In the expression: randomNumber ((- 1.0), 1.0)

Main.hs:8:56:
    No instance for (Fractional a0) arising from the literal ‘1.0’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Fractional Double -- Defined in ‘GHC.Float’
      instance Fractional Float -- Defined in ‘GHC.Float’
      instance Integral a => Fractional (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus three others
    In the expression: 1.0
    In the expression: (- 1.0)
    In the first argument of ‘randomNumber’, namely ‘((- 1.0), 1.0)’

Main.hs:9:9:
    No instance for (Show a0) arising from a use of ‘print’
    The type variable ‘a0’ is ambiguous
    Relevant bindings include points :: [a0] (bound at Main.hs:8:9)
    Note: there are several potential instances:
      instance Show Double -- Defined in ‘GHC.Float’
      instance Show Float -- Defined in ‘GHC.Float’
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 65 others
    In a stmt of a 'do' block: print points
    In the expression:
      do { points <- sequence
                       (map (\ n -> randomNumber ((- 1.0), 1.0)) [1 .. 10]);
           print points }
    In an equation for ‘main’:
        main
          = do { points <- sequence
                             (map (\ n -> randomNumber ((- 1.0), 1.0)) [1 .. 10]);
                 print points }
Failed, modules loaded: none.

最佳答案

为什么会发生这种情况?

所有错误中都有一条特定消息:类型变量“a0”不明确。为什么会这样呢?好吧,randomNumber 适用于 Random 的任何实例,并且有很多实例。 -1.0 包括 Num,因为您希望能够对某个值求反。此外,值 1.0 本身得出的结论是您的类型需要是 Fractional 的实例。这减少了在这种情况下可以使用的类型数量,但它仍然不是唯一的:FloatDouble 和其他四种类型都是合适的。

此时,编译器放弃,需要告诉它您实际想要使用哪个实例。

如何解决这个问题

有很多方法可以解决这个问题。首先,我们可以引入一个小辅助函数:

-- fix a to double
randomDouble :: (Double, Double) -> IO Double
randomDouble = randomNumber

或者我们可以注释不明确的 1.0 的类型:

points <- sequence (map (\n -> randomNumber ((-1.0), 1.0 :: Double)) [1..10])
--                                                   ^^^ as a Double

或者我们可以注释列表的类型:

print (points :: [Double])
--     ^^^^^^^^^^^^^^^^^^  points is a list of Doubles

您选择哪一个实际上或多或少取决于风格和个人喜好。也就是说,sequence。 map f $ xs 可以写成 mapM f xs,但由于您实际上有 IO a,所以最好使用 replicateM $ randomNumber (...)mapMreplicateM 都可以在 Control.Monad 中找到。 .

TL;DR

当 GHC 因类型不明确而对你大喊大叫时,请对它们进行注释。

关于haskell - 生成随机值列表并将它们打印到 Haskell 中的标准输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26220421/

相关文章:

Haskell - zip 2 个列表

haskell - 使用 INLINABLE pragma 的缺点

haskell - 求解(两个以上)线性不等式系统

haskell - 程序程序员的功能代码片段列表?

c++ - 使用 C++ 模板实现 Haskell 的 `map` 函数的问题

Linux 中通过 Emacs/Vim 进行 Haskell 编码 : organising files into projects

haskell - 授予可遍历的 F 代数,是否可能对应用代数进行变形?

haskell - Haskell中AST的无样板注释?

haskell - 如何解码编码字字符串?

optimization - 优化Haskell程序