1
votes

I compile this code and ghc tells me "parse error (possibly incorrect indentation or mismatched brackets)" at the final line ("randSeq :: Integer -> String")

pair = randSeq n ++ " | " ++ randSeq n where do g <- newStdGen
                                             let n = randomR (1,10) g

randSeq :: Integer -> String
...

I made sure to use space for indentation. I avoided using the 'let' keyword like below but it still yields the same error

pair = randSeq n ++ " | " ++ randSeq n where n = randomR (1,10) g
                                             do g <- newSTdGen

randSeq :: Integer -> String
...
2

2 Answers

5
votes

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.

1
votes

You can't use do keyword after where. This should helps you:

randSeq :: Integer -> String
randSeq n = undefined -- I don't know how it is implemented

{- To obtain random number: -} 
randInteger :: IO Integer
randInteger =
  newStdGen >>=
    return . fst . randomR (0, 10)

pair :: IO String   
pair = randInteger >>= \ n ->
         let rs = randSeq n in
           return $ rs ++ " | " ++ rs