2010-12-09 70 views
4

我的目标是编写Haskell函数,它从输入中读取N行并将它们加入到一个字符串中。下面是第一次尝试:Haskell将[IO字符串]加入IO字符串的方式

readNLines :: Int -> IO String 
readNLines n = do 
    let rows = replicate n getLine 
    let rowsAsString = foldl ++ [] rows 
    return rowsAsString 

上。这里foldl Haskell的投诉:

不能匹配预期类型[a]' against inferred type(A1 - >乙 - > A1) - > A1 - >并[b] - > A1'

按我的理解是行的[IO String]类型,是否有可能一些如何在一个IO String加入该名单?

回答

6

再说什么ephemient指出,我认为你有一个语法问题:您正在使用的++操作的方式使它看起来像你试图调用++操作符与操作数foldl[]。把++运营商在括号中,使你的意图明显:

foldl (++) [] rows 
+0

啊,是的,这是typecheck错误的直接原因......我忽略了,因为即使OP修复后,他们仍然有另一个问题。 – ephemient 2010-12-09 19:34:16

+0

还应该注意'foldl(++)[]`与`concat`相同。 – HaskellElephant 2010-12-09 23:29:35

5

你正在寻找的是一个功能是sequence,然而,应该指出的是,

sequence (replicate n f) 

相同

replicateM n f 

foldl (++) []相当于concat。所以,你的功能是:

readNLines n = liftM concat (replicateM n getLine) 

另外,如果要保留换行:

readNLines n = liftM unlines (replicateM n getLine) 
0

replicate返回IO String操作的列表。为了执行这些操作,它们需要在IO monad中运行。所以你不想加入IO操作数组,而是依次运行它们并返回结果。

这里就是我会做

readNLines :: Int -> IO String 
readNLines n = do 
    lines <- replicateM n getLine 
    return $ concat lines 

或者,在应用性风格:

import Control.Applicative 

readNLines :: Int -> IO String 
readNLines n = concat <$> replicateM n getLine 

这两种使用一元重复(replicateM),其评估序列一元值的列表,而不是简单地返回一个动作列表

1

我可以拿出的最短答案是:

import Control.Applicative 
import Control.Monad 

readNLines :: Int -> IO String 
readNLines n = concat <$> replicateM n getLine