我对 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
的实例。这减少了在这种情况下可以使用的类型数量,但它仍然不是唯一的:Float
、Double
和其他四种类型都是合适的。
此时,编译器放弃,您需要告诉它您实际想要使用哪个实例。
如何解决这个问题
有很多方法可以解决这个问题。首先,我们可以引入一个小辅助函数:
-- 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 (...)
。 mapM
和 replicateM
都可以在 Control.Monad
中找到。 .
TL;DR
当 GHC 因类型不明确而对你大喊大叫时,请对它们进行注释。
关于haskell - 生成随机值列表并将它们打印到 Haskell 中的标准输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26220421/