2016-05-31 97 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 ...} 
相關問題