Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function declaration for Random Number Generator in Haskell

Tags:

random

haskell

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.

like image 712
Chris.Q Avatar asked May 07 '26 04:05

Chris.Q


1 Answers

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.

like image 180
Sibi Avatar answered May 10 '26 23:05

Sibi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!