我的目标是编写Haskell函数,该函数从输入中读取N行并将它们连接在一个字符串中。以下是第一次尝试:
readNLines :: Int -> IO String
readNLines n = do
let rows = replicate n getLine
let rowsAsString = foldl ++ [] rows
return rowsAsString
这里有关于foldl
的抱怨:
无法匹配预期类型
[a]' against inferred type
(a1 - > b - > a1) - > a1 - > [b] - > A1'
据我所知,行的类型为[IO String]
,是否有可能将这样的列表连接到一个IO String
?
答案 0 :(得分:19)
您正在寻找sequence :: (Monad m) => [m a] -> m [a]
。
(可能是liftM :: Monad m => (a1 -> r) -> m a1 -> m r
和unlines :: [String] -> String
。)
答案 1 :(得分:6)
除了ephemient指出的,我认为你有一个语法问题:你使用++
运算符的方式使你看起来像是试图用操作数{{调用++
运算符1}}和foldl
。将[]
运算符放在括号中以明确您的意图:
++
答案 2 :(得分: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)
答案 3 :(得分:1)
我能想出的最短答案是:
import Control.Applicative
import Control.Monad
readNLines :: Int -> IO String
readNLines n = concat <$> replicateM n getLine
答案 4 :(得分: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
这两个都使用monadic replicate(replicateM),它按顺序计算monadic值列表,而不是简单地返回一个动作列表