Reputation: 662
my goal is to write Haskell function which reads N lines from input and joins them in one string. Below is the first attempt:
readNLines :: Int -> IO String
readNLines n = do
let rows = replicate n getLine
let rowsAsString = foldl ++ [] rows
return rowsAsString
Here haskell complaints on foldl
:
Couldn't match expected type
[a]' against inferred type
(a1 -> b -> a1) -> a1 -> [b] -> a1'
As I understand type of rows is [IO String]
, is it possible some how join such list in a single IO String
?
Upvotes: 4
Views: 4170
Reputation: 14227
The shortest answer I can come up with is:
import Control.Applicative
import Control.Monad
readNLines :: Int -> IO String
readNLines n = concat <$> replicateM n getLine
Upvotes: 1
Reputation: 45476
replicate
returns a list of IO String
actions. In order to perform these actions, they need to be run in the IO monad. So you don't want to join an array of IO actions, but rather run them all in sequence and return the result.
Here's what I would do
readNLines :: Int -> IO String
readNLines n = do
lines <- replicateM n getLine
return $ concat lines
Or, in applicative style:
import Control.Applicative
readNLines :: Int -> IO String
readNLines n = concat <$> replicateM n getLine
Both of these use the monadic replicate (replicateM), which evaluates a list of monadic values in sequence, rather than simply returning a list of actions
Upvotes: 0
Reputation: 9891
The functions you are looking for is is sequence
, however it should be noted that
sequence (replicate n f)
is the same as
replicateM n f
And foldl (++) []
is equivalent to concat
. So your function is:
readNLines n = liftM concat (replicateM n getLine)
Alternatively if you want to preserve line breaks:
readNLines n = liftM unlines (replicateM n getLine)
Upvotes: 5
Reputation: 12077
Besides what ephemient points out, I think you have a syntax issue: The way you're using the ++
operator makes it look like you are trying to invoke the ++
operator with operands foldl
and []
. Put the ++
operator in parentheses to make your intent clear:
foldl (++) [] rows
Upvotes: 6
Reputation: 204926
You're looking for sequence :: (Monad m) => [m a] -> m [a]
.
(Plus liftM :: Monad m => (a1 -> r) -> m a1 -> m r
and unlines :: [String] -> String
, probably.)
Upvotes: 20