'random number generator function returns a nested tuple in haskell

I am trying to understand why my haskell function returns a nested tuple, and I cannot seem to wrap my head around the problem.

I have this function that generates a random binary Int

test :: StdGen -> (Int, StdGen)
test g = do
  let (i, g') = randomR (0, 1) g
  return (i, g')

However, I cannot compile this unless I change the function to return a nested tuple, like so:

test :: StdGen -> (Int, (Int, StdGen))

If I do so, I have to get the snd element in the returned tuple, to get the desired result:

g = mkStdGen 5
(i, g') = snd test g

How do I make my test function return a single tuple with the random binary and a new generator (i, g)? What am I missing?



Solution 1:[1]

Unlike other languages, where return is a keyword that means to immediately exit a procedure and hand off a value to the caller, in Haskell return is just another function, and it can do fairly arbitrary things. In Haskell, the way to choose what value to hand off to the caller is to simply state it as the value on the right-hand side of an equals sign. So, deleting return makes your code work:

test :: StdGen -> (Int, StdGen)
test g = do
  let (i, g') = randomR (0, 1) g
  (i, g')

However, this way of spelling test is a little misleading. Most Haskell programmers use do only when they are working with the monadic operators (named return, coincidentally, and (>>=)) and want a better syntax for them. You are not doing that here; the fact that this code desugars to something sensible would probably surprise some readers. Instead, I recommend explicitly using the code that it desugars to, which isn't even longer:

test g =
  let (i, g') = randomR (0, 1) g
  in (i, g')

Additionally, this let X = ... in X is probably better just written with the content of the definition of X:

test g = randomR (0, 1) g

As a matter of aesthetics, some people will eta reduce this (and some won't -- I am a lot less attached to this suggested change than the previous ones):

test = randomR (0, 1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Daniel Wagner