I was playing around with the random function that gives an infinite list of random values as shown in Chapter 9 of "Learn You a Haskell for Great Good". The code goes like this:
randoms' :: (RandomGen g, Random a) => g -> [a]
randoms' gen = let (value, newGen) = random gen
in value : randoms' newGen
In order to record the random generators, I changed randoms'
a bit to the following:
randoms'' :: (RandomGen g, Random a) => g -> [(a, g)]
randoms'' gen = let (value, newGen) = random gen
in (value, newGen) : randoms'' newGen
It works as expected.
Then I rewrote it in the style of list comprehension:
randoms''' :: (RandomGen g, Random a) => g -> [(a, g)]
randoms''' gen = random gen : [random gen' | (_, gen') <- randoms''' gen]
This time, the complier gives the error: Could not deduce (Random a0) arising from a use of ‘randoms'''’...... The type variable ‘a0’ is ambiguous...
However, if I specify the type of randoms'''
with concrete types, e.g.,
randoms''' :: StdGen -> [(Int, StdGen)]
randoms''' gen = random gen : [random gen' | (_, gen') <- randoms''' gen]
it works fine again and gives exactly the same result as randoms''
.
I wonder why the type inference works for randoms''
but fails for randoms'''
. Can anyone tell me why these two are not equivalent and how to fix the code of randoms'''
?
Furthermore, I experimented with the test code having the similar structure:
generate :: (Integral a, RealFrac b) => a -> (b,a)
generate m = let x = 1.2^^m in (x, ceiling x)
foo :: (Integral g, RealFrac a) => g -> [(a,g)]
foo gen = let (value, newGen) = generate gen
in (value, newGen) : foo newGen
foo' :: (Integral g, RealFrac a) => g -> [(a, g)]
foo' gen = generate gen : [generate gen' | (_, gen') <- foo' gen]
foo'' :: (Integral g, RealFrac a) => g -> [(a, g)]
foo'' gen = [generate gen' | gen' <- gen : map snd (foo'' gen)]
It turns out foo
, foo'
and foo''
all work fine. Apparently, it is not a problem of monomorphism vs polymorphism. It seems to be a problem specific to random
.
randoms'''
((_, gen') <- ...
) so the compiler has no idea at which type to instantiate the use ofrandoms'''
; there is no reason for it to pick the same typea
that is the output, nor any other particular type, so it is ambiguous. In the monomorphic case, there is no instantiation possible - naturally it may only pickInt
for the recursive case. – user2407038