繁体   English   中英

Haskell IO-要列出的文件行

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM