我刚刚开始学习Haskell,使用“了解大好的Haskell”这本书并完成阅读第9章“输入和输出”。但是当我尝试一个例子时,我遇到了一些奇怪的问题,可以粗略地描述为三个步骤。
1)本书中的示例代码是
finiteRandoms :: (RandomGen g, Random a, Num n) => n -> g -> ([a], g)
finiteRandoms 0 gen = ([], gen)
finiteRandoms n gen =
let (value, newGen) = random gen
(restOfList, finalGen) = finiteRandoms (n-1) newGen
in (value:restOfList, finalGen)
但这不能编译。错误消息是
/Users/learn_haskell/randomness.hs:12:15:
Could not deduce (Eq n) arising from the literal `0'
from the context (RandomGen g, Random a, Num n)
bound by the type signature for
finiteRandoms :: (RandomGen g, Random a, Num n) =>
n -> g -> ([a], g)
at /Users/learn_haskell/randomness.hs:10:18-69
Possible fix:
add (Eq n) to the context of
the type signature for
finiteRandoms :: (RandomGen g, Random a, Num n) =>
n -> g -> ([a], g)
In the pattern: 0
In an equation for `finiteRandoms': finiteRandoms 0 g = ([], g)
Failed, modules loaded: none.
2)我根据错误消息更改了代码:
finiteRandoms :: (RandomGen g, Random a, Eq n, Num n) => n -> g -> ([a], g)
finiteRandoms 0 gen = ([], gen)
finiteRandoms n gen =
let (value, newGen) = random gen
(restOfList, finalGen) = finiteRandoms (n-1) newGen
in (value:restOfList, finalGen)
编译很好,但是如果我运行这个函数会出错
*Main> finiteRandoms 5 (mkStdGen 10)
<interactive>:18:1:
No instance for (Random a0) arising from a use of `finiteRandoms'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
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: finiteRandoms 5 (mkStdGen 10)
In an equation for `it': it = finiteRandoms 5 (mkStdGen 10)
3)最后,我根据前面的例子更改了代码。
finiteRandoms :: Int -> StdGen -> ([Int], StdGen)
finiteRandoms 0 gen = ([], gen)
finiteRandoms n gen =
let (value, newGen) = random gen
(restOfList, finalGen) = finiteRandoms (n-1) newGen
in (value:restOfList, finalGen)
此时一切似乎都很好。
基本上,我知道为什么第三段代码是正确的,但我不太清楚前两步中出了什么问题。这些错误信息的真正含义是什么?顺便说一下,我在Emacs中使用Haskell模式,我不确定这是否相关。
答案 0 :(得分:4)
第一个示例不起作用,因为您将变量n
与0进行模式匹配。因此您必须将约束Eq
正确地放置到typecheck。 Eq
类型类定义函数==
,如果要检查两个变量是否相等,则需要它。
在第二个示例中,编译器无法确定所需的确切输出类型。但是如果你明确地给它,它将正常工作:
ghci> finiteRandoms 4 (mkStdGen 10) :: ([Int], StdGen)
([-2776415066813205131,-8883108635655729860,-2410613080667970943,-2829092335322664428],587898465 1924298326)
因为第二个示例中的类型签名是多态的,所以您必须指定要获得结果的确切类型。
您还可以获取其他类型的随机数,以防您明确指定:
ghci> finiteRandoms 4 (mkStdGen 10) :: ([Double], StdGen)
([0.7560066907787318,0.7768262448447909,0.3681854379838826,0.9076550534223906],587898465 1924298326)
第三个示例没有任何问题,因为在类型签名本身中,您已明确提到了所需的确切输入和输出类型。此外,不应该注意到,第三个例子不是多态的。