2016-05-31 100 views
1

我在Haskell中有以下代码,它在bookFromFile函数的第一行给出了一个错误。我究竟做错了什么?Haskell - 从文件中读取数据并存储到容器中

错误代码如下。

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) 

奇怪的是,(智力,字符串,字符串,字符串,字符串,字符串,整数)是不是连我都为本书定义的类型。 错误消息:

* 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"); 
      .... } 
+0

此代码读取像C转化为哈斯克尔,不地道的哈斯克尔.... Y上的小记录类型你应该利用Haskell的懒惰,'readFile','lines'和一些纯函数,这将真正展示选择Haskell的理由。 – jamshidh

回答

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) 
2

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

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

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

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 ...} 
相关问题