2016-06-04 13 views
-2

Im Anfänger und im Versuch, Dateien von meinem Ordner „Papiere“ (im selben Pfad, der die Skripte) zu lesen, aber ich die nächsten Fehler habe:Wie kann ich Dateien in Haskell lesen?

Couldn't match expected type ‘[FilePath]’ 
       with actual type ‘IO [FilePath]’ 
    In the first argument of ‘leerDocumentos’, namely ‘pathFicheros’ 
    In the first argument of ‘return’, namely 
     ‘(leerDocumentos pathFicheros)’ 

Vielleicht ist das nicht der Fehler, ich habe auf meinem Code, so hoffe ich, dass jemand mir helfen kann, mein Modul zu vervollständigen.

Der Code meiner Leser:

module LeerDocumentos2 where 
import System.Directory 
import System.IO.Unsafe 
import System.IO() 
import Documento 


reader :: IO [Documento] 
reader = do 
    setCurrentDirectory "papers" 
    directorio <- getCurrentDirectory 
    putStrLn directorio  -- Directorio donde estan los documentos 
    let pathFicheros = getDirectoryContents directorio 
    return (leerDocumentos pathFicheros) 

leerDocumentos :: [FilePath] -> [Documento] 
leerDocumentos [] = [] 
leerDocumentos (x:xs) = do 
        let documento = unsafePerformIO (leerDocumento x) 
        [documento]++ leerDocumentos xs 
leerDocumento :: String -> IO Documento 
leerDocumento ruta = do 
       putStrLn ruta 
       texto <- readFile ruta 
       let docuAux = lines texto 
       let revista = obtenerRevista docuAux 
       let idd = obtenerID docuAux 
       let anno = obtenerAnno docuAux 
       let titulo = obtenerTitulo docuAux 
       let resumen = obtenerResumen docuAux 
       let secciones = obtenerSecciones docuAux 
       let documento = D (revista,idd,anno,titulo,resumen,secciones) 
       return documento 

obtenerRevista :: [String] -> String 
obtenerRevista [] = [] 
obtenerRevista texto = head texto 

obtenerID:: [String] -> String 
obtenerID [] = [] 
obtenerID texto = head (drop 1 (texto)) 

obtenerAnno:: [String] -> String 
obtenerAnno [] = [] 
obtenerAnno texto = head (drop 2 (texto)) 

obtenerTitulo:: [String] -> String 
obtenerTitulo [] = [] 
obtenerTitulo texto = head (drop 4 (texto)) 

obtenerResumen:: [String] -> String 
obtenerResumen [] = [] 
obtenerResumen texto = head (drop 6 (texto)) 

obtenerSecciones :: [String]->[String] 
obtenerSecciones [] = [] 
obtenerSecciones texto = quitarSeparador (drop 8 (texto)) 

quitarSeparador :: [String] -> [String] 
quitarSeparador [] = [] 
quitarSeparador (s:sn) = if s == "--" || length s <= 1 then --Para quitar lineas blancas 
          quitarSeparador sn 
          else 
          s:quitarSeparador sn 

und dies ist der Code meines Modul Documento:

Modul Documento wo

data Documento = Documento {revista :: String, idD :: String, anno :: String, titulo :: String, resumen :: String, secciones :: [String]} deriving (Eq) 
type Documentos = [Documento] 

Dank !!

+4

Zuerst bitte vergessen Sie, dass "unsafePerfomIO" überhaupt existiert und verwenden Sie dann 'pathFicheros <- getDirectoryContents directorio' anstelle von' let' – Carsten

Antwort

0

Das Problem, das Sie haben, ist, dass Sie versuchen, eine Funktion aufzurufen, die eine [FilePath] übernimmt, aber Sie sind darin ein IO [FilePath] übergeben.

Das Problem besteht darin, dass der Wert, den Sie an die Funktion übergeben möchten, in der IO Monad gekapselt ist. Ein Wert wird im IO Monad gespeichert, wenn eine Eingabe-/Ausgabeoperation zur Berechnung verwendet wird. In diesem Fall sagt die IO Monad im Grunde, dass einige IO gemacht wurde, um den Wert zu erstellen, und daher ruft die Funktion, die den Wert erzeugt, nicht immer die gleiche Ausgabe für dieselbe Eingabe auf.

Zum Beispiel kann die Funktion getLines erhält eine Eingabezeile vom Benutzer, und da die Zeile, die der Benutzer eingibt kann nicht garantiert wird jedes Mal das gleiche sein, die Funktion gibt eine IO String eher als ein reguläres String.

In Haskell möchten Sie immer im Auge behalten, wenn Eingang/Ausgang benutzt wird. Daher arbeiten Sie im Allgemeinen nicht mit Funktionen, die einen IO-Wert annehmen und einen Nicht-IO-Wert zurückgeben, da dies einen wichtigen Kontext zerstört.

Daher wird die Verwendung der Funktion unsafePerformIO :: IO a -> a generell abgeraten, da sie eine IO-Aktion ausführt, ohne die Tatsache zu verfolgen, dass IO ausgeführt wurde.


Das ist die Theorie hinter dem Problem ist, dass Sie konfrontiert sind, jetzt, da Sie wissen, dass, können Sie herausfinden, wie sich mit dem Thema befassen.

Wenn Sie mit IO-Werten oder anderen monadischen Werten arbeiten, müssen Sie mit dem in der Monade enthaltenen Wert arbeiten und den monadischen Kontext um den Wert vorübergehend ignorieren.

Es gibt einige Möglichkeiten, wie dies getan werden kann. In Ihrem Fall werden Sie wahrscheinlich mit der do-Notation arbeiten wollen, da Sie sie bereits ein wenig benutzen.

Schauen wir uns den Abschnitt einen Blick darauf werfen, wo Sie mit Fragen sind:

reader :: IO [Documento] 
reader = do 
    setCurrentDirectory "papers" 
    directorio <- getCurrentDirectory 
    putStrLn directorio  -- Directorio donde estan los documentos 
    let pathFicheros = getDirectoryContents directorio 
    return (leerDocumentos pathFicheros) 

Insbesondere ist der Fehler, den Sie bekommen ist mit den folgenden Zeilen:

let pathFicheros = getDirectoryContents directorio 
return (leerDocumentos pathFicheros) 

Das Problem ist, dass Sie versuchen, leerDocumentos :: [FilePath] -> [Documento] aufrufen und pathFicheros übergeben, die vom Typ IO [FIlePath] ist, da es aus dem Aufruf getDirectoryContents :: FilePath -> IO [FilePath] abgerufen wird.

Was Sie tun möchten, ist eine Möglichkeit zu finden, mit pathFicheros als nur [FilePath] zu arbeiten, aber behalten Sie den E/A-Kontext.

Da Sie dies alles in einem Do-Block tun, können Sie den Operator <- verwenden, um den EA-Kontext bis zum Do-Block zu sortieren und nur den enthaltenen Wert in die Konstante pathFicheros zu übernehmen.

pathFicheros <- getDirectoryContents directorio 
return (leerDocumentos pathFicheros) 

Auf diese Weise können Sie mit pathFicheros als [FilePath], arbeiten aber den IO Kontext, in dem Wert halten, indem die reader :: IO [Documento] Funktion zurückgegeben.

Sobald Sie diese Änderung vornehmen, sollte der Code ohne Problem kompilieren.

aber Sie wollen auch Ihre Benutzung unsafePerformIO in leerDocumentos und ersetzen Sie es mit der richtigen Funktionalität im do-Block zu entfernen, die dann ein IO [Documento] statt nur ein [Documento] zurückkehren. Danach müssen Sie nur die Verwendung von return am Ende der reader entfernen, so dass in den Sachen innerhalb der return, und Sie sollten gut sein.

Ich empfehle, dass Sie etwas lesen und experimentieren mit Monaden, und gemeinsame Funktionen arbeiten mit Monaden arbeiten, wie die "bind" -Funktion >>=, und das sollte Ihnen helfen, ein besseres Verständnis zu bekommen, wie man mit Monaden arbeitet wie IO.

Monaden sind in Haskell zunächst ein schwieriges Konzept, aber das Beste, was Sie tun können, um besser mit ihnen arbeiten zu können, ist, sie zu lesen und zu versuchen, die Ideen umzusetzen, über die Sie lesen.