Rog Matthews
Rog Matthews

Reputation: 3247

How can i use the loop without any error in this code?

This is a program so that the GHC takes a number n from user and then it forms a list of n numbers which again are given by the user. this code is showing some parse error for loop. How can i remove that error?

import System.IO

main = do 
   putStrLn "Please enter the number"
   number <- readLn :: IO Int
   putStrLn $ "The num is:" ++ show number
   loop number
   xs <- sequence [readLn :: IO Int]
   putStrLn xs

loop:: Int -> IO ()
loop n = if 0==n then return () else return loop (n-1)

Upvotes: 1

Views: 137

Answers (3)

Dan Burton
Dan Burton

Reputation: 53715

If I understand your intent correctly, you meant to create a "loop" construct that would perform an action n times, and produce a list of the results. In the code you have,

loop number
xs <- sequence [readLn :: IO Int]

But these two statements are separate; you need to instead send the action you wish to be repeated to the loop as inut:

xs <- loop number readLn :: IO [Int]

Now of course you need to rewrite your loop to accept an action as a parameter

loop :: Int -> IO a -> IO [a]
loop 0 action = return []  -- don't perform the action
loop n action = do
  x <- action              -- perform the action once
  xs <- loop (n-1) action  -- then perform it (n-1) times
  return (x:xs)            -- produce the resultant list

Here I've written it with pattern matching, instead of if n == 0. I could just as easily write it with an "if" construct, but I personally tend to find those rather ugly.

But wait, maybe something like this already exists in the standard libraries. Stop...Hoogle time! Hoogling the type signature for our new loop, a -> IO a -> IO [a], we discover replicateM.

xs <- replicateM number readLn :: IO [Int]

Upvotes: 0

bzn
bzn

Reputation: 2392

There are three errors in your code. Copying it and starting it in GHC gives the following messages:

temp.hs:9:13
    Couldn't match expected type `Char' with actual type `Int'
    Expected type: String
      Actual type: [Int]
    In the first argument of `putStrLn', namely `xs'
    In the expression: putStrLn xs

This one is quite clear. putStrLn needs a String, but xs is a list of Ints. So simply using print xs instead of putStrLn xs solves the problem (print = putStrLn . show).

The next two are actually about the the same problem:

    temp.hs:13:38:
        No instance for (Monad ((->) t0))
          arising from a use of `return'
        Possible fix: add an instance declaration for (Monad ((->) t0))
        In the expression: return loop (n - 1)
        In the expression:
          if 0 == n then return () else return loop (n - 1)
        In an equation for `loop':
            loop n = if 0 == n then return () else return loop (n - 1)

temp.hs:13:45:
    Couldn't match expected type `IO ()'
                with actual type `Int -> IO ()'
    In the first argument of `return', namely `loop'
    In the expression: return loop (n - 1)
    In the expression:
      if 0 == n then return () else return loop (n - 1)

The problem is in the types. loop is of type Int -> IO (). So the first branch of the function is alright, because you return (). However, in the else branch, you return something completely different, because return is not some built-in statement of the language, but a normal function. So return loop (n - 1) first lifts your loop function into the monad and than applies it to (n - 1).

Instead, what you want is:

loop n = if n == 0 then return () else loop (n - 1)

Also note that you don't need 0 == n in Haskell, as there is no way to accidentally use assignment instead of equality comparison (it doesn't compile).

Edit: As the other answers pointed out, loop isn't really doing anything - it only calls itself n-1 times and then returns ().

Upvotes: 0

dave4420
dave4420

Reputation: 47062

In addition to what the other answers have said:

You don't need to write a loop function.

import System.IO

main = do 
   putStrLn "Please enter the number"
   number <- readLn :: IO Int
   putStrLn $ "The num is:" ++ show number
   xs <- sequence (replicate number (readLn :: IO Int))  -- pay attention to this line
   print xs

So we start with readLn. replicate makes a list of number readLns. (Depending on your perspective, you might think this is the clever bit.)

The clever bit: sequence takes that list of IO actions, and turns it into one big IO action. Each readLn happens in turn, and the return values are collected and returned in a list.

Upvotes: 2

Related Questions