2016-05-31 9 views
1

Ich habe den folgenden Code in Haskell, der mir einen Fehler in der ersten Zeile der Funktion bookFromFile gibt. Was mache ich falsch?Haskell - Lesen von Daten aus Datei und Speichern in einem Container

Der Fehlercode ist unten.

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) 

Merkwürdigerweise (Int, String, String, String, String, String, Int) ist nicht einmal der Typ I für Buch definiert haben. Fehlermeldung:

* 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

Dieser Code liest sich wie C zu Haskell umgewandelt, nicht idiomatischen Haskell .... Y Sie sollten Haskell Faulheit, 'ReadFile',' Linien' und eine Reihe von reinen Funktionen nutzen, die wirklich den Grund zeigen würden, Haskell über C zu wählen. – jamshidh

Antwort

3

gibt es drei kleine Probleme:

  • bookFromFile Bedürfnisse in IO sitzen - Sie diese sehen können, weil Sie Funktionen wie hGetLine und putStr
  • , wenn Sie es dann verwenden Sie b <- bookFromFile... anstelle von let b = bookFromFile ...
  • und Sie müssen return das Tupel

Sie können auch so

von vielen der (...) loszuwerden
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

Die Art Signatur von bookFromFileHandle->IO Book sein muss, da diese Funktion IO verwendet.

Da die Funktion in IO ist, sollten Sie sie nicht mit let b = .... aufrufen, sondern b <- .... verwenden.

Sie müssen auch return in der letzten Zeile der Funktion verwenden, um den Wert tatsächlich in den für die Rückgabe benötigten IO zu wickeln.

1

bookFromFile richtig so viel von dem Denken rein wie möglich machen sollte, vielleicht so etwas wie diese:

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 

Es wäre grundsätzlich das gleiche, aber schöner, wenn man ein wenig Satzart gemacht für Book

data Book = Book {isbn :: Int, title :: String ...} 
Verwandte Themen