Reputation: 21
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
.
Upvotes: 2
Views: 446
Reputation: 105915
(_, gen') <- randoms''' gen
Which type has _
here? You probably think it should be the a
given in randoms'''
's signature. However, it's arbitrary. It might be ()
, it might be Char
. Everything could work here, since you don't use it anyway. We can force it to have the same type as random gen'
:
randoms''' gen = random gen : [random gen' `asTypeOf` x | x@(_, gen') <- randoms''' gen]
asTypeOf
is a standard function and basically a type constrained version of const
:
asTypeOf :: a -> a -> a
asTypeOf = const
With this function, we can determine the type of x
and therefore the type of _
, since the type of random gen'
is known.
Upvotes: 2