5

What is wrong with the following code? I just wanted to connvert input in the following format in a file: n - count of test cases // n numbers n1 n2 (read via stdin) into list of integers and display it?

socks :: Int -> Int
socks x = x + 1
strToInt = read :: String -> Int
strLToIntL :: [String] -> [Int]
strLToIntL xs = map (strToInt) xs
main = do
    n <- readLn :: IO Int
    mapM_ putStrLn $ map show $ strLToIntL $ fmap (take n . lines) getContents

I am getting the compile error when i run it:

Couldn't match expected type `Char' with actual type `[Char]'
Expected type: String -> [Char]
  Actual type: String -> [String]
In the second argument of `(.)', namely `lines'
In the first argument of `fmap', namely `(take n . lines)'
1
  • 2
    Why not break that long line up? I think you'll find the problem very quickly if you use multiple expressions and add type signatures to each assignment. Once you've found the problem you can reduce it back down into a more compact form. Commented Dec 24, 2013 at 5:49

3 Answers 3

8

The problem is that

getContents :: IO String

so

fmap (take n . lines) getContents :: IO [String]

This can't be fed to something expecting a [String]. To fix this you need to "bind" the IO action. Using do notation you could write this as

main = do
  n <- readLine :: IO Int
  input <- fmap (take n . lines) getContents
  mapM_ putStrLn . map show . strLToIntL $ input

You could change that last line to just

 mapM print . strLToIntL $ input
Sign up to request clarification or add additional context in comments.

Comments

2

Here's your code corrected as written, since you're using a monad its easier to unpack the values using as local binds instead of using a functor.

socks :: Int -> Int
socks x = x + 1

strToInt :: String -> Int
strToInt = read

strLToIntL :: [String] -> [Int]
strLToIntL xs = map (strToInt) xs

main :: IO ()
main = do
   n <- readLn
   contents <- getContents
   mapM_ putStrLn $ map show $ strLToIntL $ take n $ lines contents

I think what you're trying to do is read a integer n and then subsequently read n lines containing integers from stdin. There are a couple more idiomatic ways to do this, for example:

import Control.Monad

main :: IO [Integer]
main = do
  n <- readLn
  forM [1..n] (const readLn)

1 Comment

As you're throwing the list of numbers away with const, why not use replicateM: main = readLn >>= flip replicateM readLn
0

Wanted to post this relevant example; it reads input from stdin until ":q" is entered.

-- | internally sets the initial state
-- | to give the illusion that no state is being passed,
-- | when in fact, the state is set inside the function.
start = 
    -- | calls the start below, not self
    -- | this is tail recursive; initial state 
    -- | is provided, []
    start []

    where 
        -- | this start carries the state along with it
        start initialState = do {
            putStrLn "Enter a number: ";
            raw_input <- getLine;

            -- | stop if ":q" entered.
            if (raw_input == ":q") then
                return ()
            else do { 
                num <- pure (read raw_input :: Int);
                newState <- pure (initialState ++ [num]);
                putStrLn (show newState);
                start newState;
            }            
        }

main = 
    start

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.