Haskell - 从文件中读取数据并存储到容器中
问题描述:
我在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");
.... }
答
有三个小问题:
-
bookFromFile
需求IO
坐 - 你可以看到这一点,因为你使用的功能,如hGetLine
和putStr
- ,当你再使用它,你必须使用
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)
答
的bookFromFile
类型签名必须是Handle->IO Book
,因为该函数使用IO。
此外,由于该功能在IO中,因此不应使用let b = ....
来调用它,而应使用b <- ....
。
您还需要在函数的最后一行使用return
实际将值包装在返回所需的IO中。
答
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 ...}
此代码读取像C转化为哈斯克尔,不地道的哈斯克尔.... Y上的小记录类型你应该利用Haskell的懒惰,'readFile','lines'和一些纯函数,这将真正展示选择Haskell的理由。 – jamshidh