where is used to bind variables to new values, as in
f x = ....
where n = ...
m = ...
g y = ...
In particular, where can not run IO actions: at most, it can define e.g. m to be such an action. The Haskell type system basically forces you to specify an ordering between IO actions, typically done using do. If Haskell allowed a where do g <- ... it would not be clear when to run this action respect to the other actions: for example,
f x = do print 1
print 2
print n
print 4
where n <- do print "hello!" -- hypothetical Haskell syntax
return 3
could mean
f x = do print 1
n <- do print "hello!"
return 3
print 2
print n
print 4
as well as
f x = do print 1
print 2
n <- do print "hello!"
return 3
print n
print 4
Back to your code, you can simply change it into a single do:
pair :: IO String
pair = do g <- newSTdGen
let n = randomR (1,10) g
return (randSeq n ++ " | " ++ randSeq n)
By the way, there's a library function randomRIO which does the same number generation, so you can simply use
pair :: IO String
pair = do n <- randomRIO (1,10)
return (randSeq n ++ " | " ++ randSeq n)
Keep in mind that the above generates one random number, and uses it twice. If you intended to use two independent random numbers then use instead
pair :: IO String
pair = do n1 <- randomRIO (1,10)
n2 <- randomRIO (1,10)
return (randSeq n1 ++ " | " ++ randSeq n2)
Finally the code above assumes that randSeq returns a String and not an IO String. If it does return an IO String, you have to order these two actions as well.
pair :: IO String
pair = do n1 <- randomRIO (1,10)
n2 <- randomRIO (1,10)
s1 <- randSeq n1
s2 <- randSeq n2
return (s1 ++ " | " ++ s2)
Or, using some library function to prettify the code a bit,
pair :: IO String
pair = do s1 <- randomRIO (1,10) >>= randSeq
s2 <- randomRIO (1,10) >>= randSeq
return (s1 ++ " | " ++ s2)
or even
pair :: IO String
pair = do s1 <- randomSeq
s2 <- randomSeq
return (s1 ++ " | " ++ s2)
where -- this does not run the IO action, it only gives it a name
randomSeq = randomRIO (1,10) >>= randSeq
Finally, pair can not return a String without the IO monad, since it is not a constant string, but an action which generates a random string every time it is run.