Domanda

Attualmente sto lavorando al progetto con Haskell e ho riscontrato dei problemi. Dovrei leggere e inserire in una lista ogni riga in un & Quot; dizionario.txt & Quot; file, ma non riesco a farlo. Ho questo codice:

main = do
    let list = []
    loadNums "dictionary.txt" list

loadNums location list = do
    inh <- openFile location ReadMode
    mainloop inh list
    hClose inh

mainloop inh list = do 
    ineof <- hIsEOF inh
    if ineof
        then return ()
        else do 
            inpStr <- hGetLine inh
            inpStr:list
            mainloop inh list

Dovrebbe ottenere ogni riga (so che ottiene ogni riga, poiché sostituisce " inpStr: list " con un " putStrLn inpStr " funziona correttamente, visualizzando tutte le righe) e inseriscilo in un elenco ma viene visualizzato il seguente errore:

Couldn't match expected type `IO' against inferred type `[]'

Probabilmente perché hGetLine non è una stringa, ma una stringa IO, che non ho idea di come gestire per ottenere una stringa corretta che posso inserire nel mio elenco. Non ho idea di come possa essere risolto, o quale sia esattamente il problema, ma se qualcuno ha idea di come ottenere correttamente ogni riga di un file in un elenco, lo apprezzerei.

Grazie in anticipo!

È stato utile?

Soluzione

Nella riga in cui si verifica l'errore, Haskell si aspetta " IO a " ;, ma gli stai dando un []. Semplificando molto le cose, su un blocco do sulla monade IO, ogni riga è:

  • Qualcosa che restituisce un valore di " IO a " genere; il valore di " a " il tipo al suo interno viene scartato (quindi il " a " è spesso " () ")
  • A < - espressione, che fa la stessa cosa ma invece di scartare il valore di " a " type gli dà il nome a sinistra di < -
  • Un let, che non fa altro che dare un nome a un valore

In questo blocco, il " hGetLine inh " restituisce un " IO String " ;, e la stringa al suo interno viene estratta e data il nome inpStr. La riga successiva, poiché non è né let né & Lt; -, dovrebbe avere un tipo & Quot; IO a & Quot ;, che non ha (causando così l'errore del compilatore). Quello che puoi fare invece, dato che hai già la String, è let:

let list' = inpStr:list

Questo crea un nuovo elenco costituito dalla stringa seguita dall'elenco originale e gli dà il nome di " list '" ;.

Cambia la seguente riga per usare " list '" invece di " list " (passando così il nuovo elenco). Quella linea chiama (ricorsivamente) mainloop, che leggerà un'altra linea, chiamerà se stessa e così via. Dopo aver letto l'intero file, restituirà qualcosa con & Quot; IO () & Quot; genere. Questo & Quot; IO () & Quot; verrà restituito al blocco do su loadNums. Congratulazioni, hai appena creato un elenco con le righe lette dal file, in ordine inverso (dal momento che stavi accodando in testa all'elenco), e quindi non hai fatto nulla.

Se vuoi farci qualcosa, cambia " return () " a " lista di ritorno " ;; il ritorno genererà un valore di tipo " IO [String] " ;, con l'elenco al suo interno (return non fa altro che incapsulare il valore), che puoi estrarre su loadNums con < - sintassi.

Il resto è lasciato come esercizio al lettore.

Altri suggerimenti

A meno che questo non sia per i compiti o cose del genere, non c'è motivo di fare così tanti sforzi. Riutilizzare è pigro!

getLines = liftM lines . readFile

main = do
    list <- getLines "dictionary.txt"
    mapM_ putStrLn list

Ma mentre sembra che tu stia ancora imparando Haskell, è importante per te capire cosa ha scritto CesarB.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top