Question

I'm trying to create a function which allows the user to input a list of strings. The function takes the length and allows the user to input length-1 more lines. Then each line is checked to ensure it is the same length as the original line. However, I'm having a few problems and that I can't find a solution to.

The problems are that I can input more than count-1 lines and the length isn't being calculated as I expected.. for example if I input ["12","13"] and then ["121","13"] the error is given, although they are the same length!

read :: IO [Line]
read = do
  line <- getLine
  let count = length line
  lines <- replicateM (count-1) $ do
    line <- getLine
    if length line /= count
    then fail "too long or too short"
    else return line
  return $ line : lines

Line is of type String.

readLn gives a parse error.

Was it helpful?

Solution

It sounds to me like you're getting confused about the difference between getting a line as a String and reading/parsing a line of input as a custom type. You are using getLine, which always returns exactly the String that the user types. Compare:

Prelude> fmap length getLine
["12","13"]
11
Prelude> length "[\"12\",\"13\"]" -- explanation of the 11
11
Prelude> fmap length (readLn :: IO [String])
["12","13"]
2
Prelude> length ["12", "13"] -- explanation of the 2
2

As demonstrated here, you probably want to use readLn, which first gets a line of input and then parses it with read.

-- defined in the Prelude
readLn = do
    s <- getLine
    return (read s)

If I modify your code to include the imports and definitions below:

import Control.Monad
type Line = [String]

...and to call readLn instead of getLine, then I can type the literal lines ["12","13"] and ["121","13"] without errors.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top