kaiya
kaiya

Reputation: 312

Read n lines input with Haskell

I am trying to learn to write Haskell programs. I am failing to read n lines input.

The input is

n
a b (<----- n times)

where n, a, b are numbers.

I tried

input = []

readString 0 = return()
readString n =
 do
  z <- getLine
  z:input
  readString (n-1)

main = do
 n <- getLine
 readString n

which throws errors. How do I looped read correctly in Haskell?

Upvotes: 2

Views: 365

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 152837

Haskell is immutable: once you write

input = []

then input is [] forever and ever, amen. You could use the same technique you used for having a "changing" value of n to have a "changing" value of input, that is, pass it as an argument to readString:

readString 0 input = return input
readString n input = do
  z <- getLine
  readString (n-1) (z:input)

If you do this, you will discover that the lines you input get put into input starting from the end -- so they come out in reverse order! (If your code snippet had worked, it would also have behaved this way.) One easy fix would be to change the base case:

readString 0 input = return (reverse input)

A more idiomatic fix would be to do away with the argument entirely, simply returning things in the right order in the first place:

readString 0 = return []
readString n = do
  z <- getLine
  zs <- readString (n-1)
  return (z:zs)

As you get comfortable with the standard library, you might first graduate to

readString 0 = return []
readString n = liftA2 (:) getLine (readString (n-1))

and then to skipping the definition of readString entirely in favor of rewriting main:

main = do
  n <- readLn
  lines <- replicateM n getLine
  ...

Upvotes: 8

Related Questions