Domanda

ho scritto un mucchio di codice in Haskell per creare un indice di un testo. La funzione superiore è simile al seguente:

index :: String -> [(String, [Integer])]
index a = [...]

Ora voglio dare questa funzione una stringa di leggere da un file:

index readFile "input.txt"

Il che non funziona perché readFile è di tipo FilePath -.> IO Stringa

  

tipo non poteva competere previsto 'String'   contro il tipo derivato 'IO String'

vedo l'errore, ma non riesco a trovare alcuna funzione con il tipo:

IO String -> String

Credo che la chiave del successo risiede da qualche parte sotto alcune Monadi, ma non riuscivo a trovare un modo per risolvere il mio problema.

È stato utile?

Soluzione

Si può facilmente sufficiente scrivere una funzione che chiama l'azione readFile, e passa il risultato alla funzione indice.

readAndIndex fileName = do
    text <- readFile fileName
    return $ index text

Tuttavia, la monade IO contamina tutto ciò che lo utilizza, per cui questa funzione ha il tipo:

readAndIndex :: FilePath -> IO [(String, [Integer])]

Altri suggerimenti

C'è una buona ragione per cui non v'è tale funzione.

Haskell ha il concetto di purezza funzionale. Ciò significa che una funzione restituirà sempre lo stesso risultato quando viene chiamato con gli stessi parametri. Il solo luogo in cui è consentito IO è dentro la monade IO.

Se c'era una funzione *

index :: IO String -> String

allora potremmo improvvisamente fare azioni IO ovunque chiamando, ad esempio:

index (launchMissiles >> deleteRoot >> return "PWNd!")

purezza funzionale è una funzione molto utile che non vogliamo perdere, in quanto permette al compilatore di riordinare e funzioni inline molto più liberamente, si può essere innescato da diversi nuclei senza cambiare la semantica e dà anche la programmatori un senso di sicurezza dal momento che, se si può sapere che cosa una funzione può e non può fare dal suo tipo.

* In realtà ci è una tale funzione. Si chiama unsafePerformIO e si chiama che per molto, molto buone ragioni. Non utilizzare a meno che non si è sicuri al 100% di quello che state facendo!

Beh, non è possibile liberarsi della parte IO monade IO String. Ciò significa che si dovrà fare il vostro IO [(String, [Integer])] funzione di ritorno.

Mi consiglia di imparare di più su monadi, ma per ora si può farla franca con la funzione liftM:

liftM index (readFile "input.txt")

liftM ha questa firma:

liftM :: Monad m => (a -> b) -> m a -> m b

Si impiegano una funzione non monadico e la trasforma in una funzione monadica.

fmap index $ readFile "input.txt"

o

readFile "input.txt" >>= return . index

Si consiglia di guardare in monade e funtori

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