I just began to learn Haskell using the book "Learn You a Haskell for Great Good" and finished reading the Chapter 9 "Input and Output". But when I tried out one example, I had some weird problems, which can be roughly described as three steps.
1) The example code in the book is
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)
But this cannot be compiled. The error message is
/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) I changed the code according to the error message as:
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)
The compilation is fine, but there would be error if I run this function
*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) Finally, I changed the code according to previous examples.
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)
Everything seems to be fine at this time.
Basically, I know why the third piece of code is right, but I do not quite understand what is wrong in the first two steps. What do those error messages really mean? By the way, I use Haskell mode in Emacs, I am not sure if this is relevant.
The first example doesn't work, because you are pattern matching the variable n with 0. So you have to put the constraint Eq for it to typecheck properly. Eq typeclass defines the function == and it is needed if you want to check two variables for equality.
In the second example, the compiler is not able to figure out the exact type of output you want. But in case you give it explicitly, it will work properly:
ghci> finiteRandoms 4 (mkStdGen 10) :: ([Int], StdGen)
([-2776415066813205131,-8883108635655729860,-2410613080667970943,-2829092335322664428],587898465 1924298326)
Because the type signature in the second example is polymorphic, you have to specify the exact type you want to get the result.
You can also get random number of other type, in case you specify them explicity:
ghci> finiteRandoms 4 (mkStdGen 10) :: ([Double], StdGen)
([0.7560066907787318,0.7768262448447909,0.3681854379838826,0.9076550534223906],587898465 1924298326)
The third example works without any problem, because in the type signature itself you have explicitly mentioned the exact input and outputs types you want. Also it should not be noted that, the third example is not polymorphic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With