[英]Haskell IO - file lines to list
我正在编写haskell程序,但IO类型遇到问题。 我的readLines函数及其应返回的类型似乎有问题。 我希望它返回一个列表,其中每个元素都是使用openDict函数打开的文件中的一行。
这是我的代码。
main :: IO ()
main = do
fileHandle <- openDict
readLines fileHandle
putStr "End of program\n"
readLines :: Handle -> [IO String]
readLines fileHandle
| isEOF <- hIsEOF fileHandle = []
| otherwise = [hGetLine fileHandle] ++ readLines fileHandle
openDict :: IO Handle
openDict = do
putStr "Enter file path: "
filePath <- getLine
openFile filePath ReadMode
这是错误:
Couldn't match type `[]' with `IO'
Expected type: IO (IO String)
Actual type: [IO String]
In the return type of a call of `readLines'
In a stmt of a 'do' block: readLines fileHandle
In the expression:
do { fileHandle <- openDict;
readLines fileHandle;
putStr "End of program" }
因此,基本上,如何将IO中的这些字符串存储在列表中?
您的readLines
函数有几个问题。
首先,在这种情况下,您不想返回[IO String]
。 这将是IO操作的列表,例如[print 1 >> return "a", print 2 >> return "b"]
,这不是您想要的。 您需要一个IO操作返回String
的列表,因此您需要使用IO [String]
。
第二,图案后卫isEof <- hIsEOF fileHandle
被检查返回的值是否hIsEOF
(这是一个IO动作)的形式为isEOF
,其中isEOF
是现在定义的变量之中。 当然, 任何事物的形式都是var
,因为变量可以是任何事物。 因此,测试始终是真实的,并且没有意义:例如,它甚至不运行IO操作。
第三,组合列表构造函数和IO操作的方式遵循当前错误的类型,因此非常混乱。
一个相当冗长的方法可以做到这一点:
readLines :: Handle -> IO [String]
readLines fileHandle = do
eof <- hIsEOF fileHandle
if eof then return []
else do line <- hGetLine fileHandle
rest <- readLines fileHandle
return (line:rest)
最后一行可以使用Applicative
语法缩短:
import Control.Applicative
readLines2 :: Handle -> IO [String]
readLines2 fileHandle = do
eof <- hIsEOF fileHandle
if eof then return []
else (:) <$> hGetLine fileHandle <*> readLines2 fileHandle
可以通过读取文件中的所有内容,然后使用lines
库功能将其拆分为列表来获取简短版本。
import Control.Applicative
readLines3 :: Handle -> IO [String]
readLines3 fileHandle = lines <$> hGetContents fileHandle
这是您可能真正想要的readLines
。
readLines :: Handle -> IO [String]
readLines h = do
isEOF <- hIsEOF h -- need to access isEOF directly, without monad, see comment about the bind
case isEOF of
True -> return [] -- the return adds the IO monad to the [String] type
False -> do
line <- hGetLine h -- need to access line separately without monad
lines <- readLines h -- recurse down
return $ line ++ lines -- return adds back the IO monad
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.