Haskell - 从文件读取数据并存储到容器中

时间:2016-05-31 20:39:12

标签: haskell

我在Haskell中有以下代码,它在bookFromFile函数的第一行给出了一个错误。我做错了什么?

错误代码低于下方。

import Data.List
import System.IO

type Book = (Int, String, String, String, String, String, String)

main = do
   inputFile <- openFile "catalogo.txt" ReadMode
   let b = (bookFromFile inputFile)
   print "done"

bookFromFile :: Handle -> Book
bookFromFile inputFile = do

   --Read&Store stuff from file
   isbn <- fmap read (hGetLine inputFile) :: IO Int
   title <- (hGetLine inputFile) 
   author <- (hGetLine inputFile)
   genre <- (hGetLine inputFile) 
   date <- (hGetLine inputFile) 
   publisher <- (hGetLine inputFile)
   summary <- (readSummary inputFile) --readSummary :: Handle -> IO String (works well)
   putStr (summary ++ "\n")

   --Construct and return a book
   (isbn, title, author, genre, date, publisher, summary)

奇怪的是,(Int,String,String,String,String,String,Int)甚至不是我为书定义的类型。 错误消息:

* Couldn't match type `IO'
                     with `(,,,,,,) Int String String String String String'
      Expected type: (Int, String, String, String, String, String, Int)
        Actual type: IO Int
    * In a stmt of a 'do' block:
        isbn <- fmap read (hGetLine inputFile) :: IO Int
      In the expression:
        do { isbn <- fmap read (hGetLine inputFile) :: IO Int;
             putStr ((show isbn) ++ "\n");
             title <- (hGetLine inputFile);
             putStr (title ++ "\n");
             .... }

3 个答案:

答案 0 :(得分:3)

有三个小问题:

  • bookFromFile需要坐在IO中 - 您可以看到这一点,因为您使用hGetLineputStr
  • 等功能
  • 当您使用它时,您使用b <- bookFromFile...而不是let b = bookFromFile ...
  • 你必须return元组

你也可以摆脱许多(...)这样的

main = do
   inputFile <- openFile "catalogo.txt" ReadMode
   b <- bookFromFile inputFile
   print "done"

bookFromFile :: Handle -> IO Book
bookFromFile inputFile = do
   --Read&Store stuff from file
   isbn <- fmap read (hGetLine inputFile)
   title <- hGetLine inputFile 
   author <- hGetLine inputFile
   genre <- hGetLine inputFile 
   date <- hGetLine inputFile 
   publisher <- hGetLine inputFile
   summary <- readSummary inputFile --readSummary :: Handle -> IO String (works well)
   putStr (summary ++ "\n")

   --Construct and return a book
   return (isbn, title, author, genre, date, publisher, summary)

答案 1 :(得分:2)

bookFromFile的类型签名必须是Handle->IO Book,因为此函数使用IO。

此外,由于该功能在IO中,因此您不应使用let b = ....来调用它,而是使用b <- ....

您还需要在函数的最后一行使用return来实际将值包装在返回所需的IO中。

答案 2 :(得分:1)

bookFromFile应该尽可能地使思维尽可能纯净,所以可能是这样的:

import Data.List
import System.IO

type Book = (Int, String, String, String, String, String, String)

bookFromStrings:: [String] -> Maybe Book
bookFromStrings [isbn,title,author,genre,date,publisher,summary] = 
       Just (read isbn,title,author,genre,date,publisher,summary)
bookFromStrings _ = Nothing

bookFromString :: String -> Maybe Book
bookFromString str = bookFromStrings (begin ++ [unlines rest]) where
      (begin, rest) = splitAt 6 (lines str)

bookFromHandle :: Handle -> IO (Maybe Book)
bookFromHandle h  = do
    str <- hGetContents h
    return (bookFromString str)

bookFromFile :: FilePath ->  IO (Maybe Book)
bookFromFile file = withFile file ReadMode bookFromHandle

如果您为Book

创建了一个小记录类型,它将基本相同但更好
 data Book = Book {isbn :: Int, title :: String ...}