Rustem Mustafin
Rustem Mustafin

Reputation: 957

Haskell: cannot compile the program

I cannot compile the following code:

main = do 
  line <- getLine
  putStrLn (work (toInt line) [0,0,0])

work n b = do
  if n == 0 
    then 
        unwords (map show b)
    else do 
        line <- getLine
        work n-1 summ (map toInt . unwords line) b

toInt :: String -> Int
toInt b = read b

toInts a = map toInt a

summ [] [] = []
summ (x:xs) (y:ys) = (x+y) ++ (summ xs ys)

Here is the error:

src\Main.hs:28:21:
Couldn't match expected type `[t0]' with actual type `IO String'
In a stmt of a 'do' expression: line <- getLine
In the expression:
  do { line <- getLine;
         work n - 1 summ (map toInt . unwords line) b }
In the expression:
  if n == 0 then
      unwords (map show b)
  else
      do { line <- getLine;
             work n - 1 summ (map toInt . unwords line) b }

What I expect from the program is to read

n
a1 b1 c1
a2 b2 c2
...
a_n b_n c_n

and output

sum(a) sum(b) sum(c)

Could You please explain why the fist occurence of getLine is OK, but the following is not?

EDIT1

I fixed the work function as follows:

work :: Int -> [Int] -> String
work n b = do
if n == 0 
    then 
        return $ unwords (map show b)
    else do 
        line <- getLine
        work (n-1) (summ toInts.words line b)

And the error is now:

src\Main.hs:27:13:
Couldn't match expected type `Char' with actual type `[Char]'
Expected type: String
  Actual type: [String]
In the expression: return $ unwords (map show b)
In the expression:
  if n == 0 then
        return $ unwords (map show b)
  else
      do { line <- getLine;
           work (n - 1) (summ toInts . words line b) }

EDIT2 Here is the final working prog:

main = do 
line <- getLine
ans <- (work (toInt line) [0,0,0])
putStrLn ans

work 0 b = return $ unwords (map show b)
work n b = do
line <- getLine
work (n-1) $ zipWith (+) (map toInt (words line)) b

toInt b = read b::Int

Upvotes: 0

Views: 293

Answers (2)

ivanm
ivanm

Reputation: 3927

It appears that work isn't in the IO monad: you can fix this by making the then part of the if-statement read: return $ unwords (map show b).

Explicit type-signatures are an extremely helpful aid to Haskell programming: whilst you technically speaking don't need them, a very common work-flow is:

  1. Specify the type a function should have
  2. Add a definition
  3. Attempt to load the file into ghci
  4. Fix any type errors that may occur.

EDIT1

The version that matches the edit in the original question is:

work :: Int -> [Int] -> IO String
work n b = do
  if n == 0 
    then 
        return $ unwords (map show b)
    else do 
        line <- getLine
        work (n-1) $ summ (map toInts $ words line) b

An improved variant is:

work :: Int -> [Int] -> IO String
work 0 bs = return . unwords $ map show bs
work n bs = do line <- getLine
               work (n-1) $ summ (map toInts $ words line) b

Note also that your definition of summ is incorrect as it uses ++ when it should use : (and is in fact identical to zipWith (+)).

Upvotes: 3

dave4420
dave4420

Reputation: 47052

You have

work n b = do
  if n == 0 
    then 
        unwords (map show b)
    else do 
        line <- getLine
        work n-1 summ (map toInt . unwords line) b

The last line there should probably be

        work (n-1) (summ (map toInt . unwords line) b)

Note the extra brackets.

There are probably other errors as well.

Upvotes: 0

Related Questions