I'm working through the following book to learn Haskell - looking in particular at the chapter on randomness:
I'm running the following as the file three-coins.hs
:
import System.Random
threeCoins :: StdGen -> (Bool, Bool, Bool)
threeCoins gen =
let (firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)
main = print ( threeCoins (mkStdGen 21) )
Which I then execute with runhaskell three-coins.hs
and get output similar to:
(True,True,True)
Now they make the point in the notes:
Notice that we didn't have to do
random gen :: (Bool, StdGen)
. That's because we already specified that we want booleans in the type declaration of the function. That's why Haskell can infer that we want a boolean value in this case.
That is cool.
Now when I run this in ghci
with the following code:
import System.Random
:{
threeCoins :: StdGen -> (Bool, Bool, Bool)
threeCoins gen =
let (firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)
:}
I get the following response:
<interactive>:6:9: error:
• Ambiguous type variable ‘t0’
prevents the constraint ‘(Random t0)’ from being solved.
• When checking that the inferred type
newGen :: forall t. Random t => StdGen
is as general as its inferred signature
newGen :: StdGen
In the expression:
let
(firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)
In an equation for ‘threeCoins’:
threeCoins gen
= let
(firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
....
in (firstCoin, secondCoin, thirdCoin)
Which is interesting. Somewhat like the error they were warning us about in the book.
So if we modify the code to put the type hints in:
import System.Random
:{
threeCoins :: StdGen -> (Bool, Bool, Bool)
threeCoins gen =
let (firstCoin, newGen) = random gen :: (Bool, StdGen)
(secondCoin, newGen') = random newGen :: (Bool, StdGen)
(thirdCoin, newGen'') = random newGen' :: (Bool, StdGen)
in (firstCoin, secondCoin, thirdCoin)
:}
That works fine - and we can test it with the following:
threeCoins (mkStdGen 21)
and get this result
(True,True,True)
Huh - that worked. So the Haskell compiler can infer from the type that we provided that we want a boolean, but ghci can't.
My question is: Why can the haskell compiler infer this type but ghci cannot?