5

I'm reading chapter 9 (More Input and More Output) of Learn You a Haskell for Great Good. Now I'm about to learn how to generate random numbers in Haskell (it's so exciting!). Here is a citation from the book:

To manually make a random generator, use the mkStdGenfunction. It has a type of mkStdGen :: Int -> StdGen. It takes an integer, and based on that, gives us a random generator. Okay then, let’s try using random and mkStdGenin tandem to get a (hardly) random number.

ghci> random (mkStdGen 100)
<interactive>:1:0:
Ambiguous type variable `a' in the constraint:
`Random a' arising from a use of `random' at <interactive>:1:0-20
Probable fix: add a type signature that fixes these type variable(s)

What’s this? Ah, right, the random function can return a value of any type that’s part of the Random type class, so we need to inform Haskell which type we want. Also let’s not forget that it returns a random value and a random generator in a pair.

The problem is that I don't get this error, in fact, I can do the following:

*Main> :m + System.Random
*Main System.Random> random (mkStdGen 100)
(-3633736515773289454,693699796 2103410263)

So my question is why can I evaluate this expression without getting the exception?

1
  • 1
    Just a short note for the future: if you actually want to use random numbers in Haskell, the mwc-random package is both faster and generates higher-quality random numbers. Commented Sep 30, 2014 at 11:42

1 Answer 1

12

I would wager a guess and say that the defaulting rules for GHCI have been extended since LYAH was written. This means that in cases where a type is ambiguous, GHCI tries to select a specific type. In this case it looks like random (mkStdGen 100) defaults to (Integer, StdGen).

If on the other hand I make a file test.hs

import System.Random

foo = random (mkStdGen 100)

... and try to load it in GHCI, I get:

test.hs:3:7:
    No instance for (Random a0) arising from a use of ‘random’
    The type variable ‘a0’ is ambiguous
    Relevant bindings include
      foo :: (a0, StdGen) (bound at test.hs:3:1)
    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: random (mkStdGen 100)
    In an equation for ‘foo’: foo = random (mkStdGen 100)
Failed, modules loaded: none.

If I wanted the same result, I would have to fix the type of foo, like so:

foo :: (Integer, StdGen)
foo = random (mkStdGen 100)

For more information on Extended Defaulting, see section 2.4.8 in the GHC docs

Sign up to request clarification or add additional context in comments.

4 Comments

One subtlety I think is probably in play here: the random method is free to modify the generator differently depending on the type. If instead the generator produced Int values, and you had an intToRandom method to use the results, then there would be no problem using it to produce polymorphic randoms. But there are very good reasons for it being the way it is, notably that different types require different amounts of randomness.
I'd bet it's how recent GHCi infers types with Show instances to display results. let r = random $ mkStdGen 100 keeps polymorphic type of random value with Random constraint r :: Random a => (a, StdGen), only when displayed is infered to Int or Integer instance.
A side note, you can turn off the extended default rules with :set -XNoExtendedDefaultRules in GHCi. With this flag set, the error occurs (although the message is different than the one in LYAH).
The error message from test.hs has to do with the monomorphism restriction. With LANGUAGE NoMonomorphismRestriction I don't get any errors. With LANGUAGE MonomorphismRestriction I get the No instance for ... error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.