2009-11-04 12 views
31

Ho scritto un mucchio di codice in Haskell per creare un indice di un testo. La funzione superiore è simile al seguente:Una funzione Haskell di tipo: IO String-> String

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

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

index readFile "input.txt" 

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

potrebbe non corrispondere previsto tipo 'String' contro tipo derivato 'IO String'

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

IO String -> String 

Immagino che la chiave del successo risieda da qualche parte sotto alcune Monadi, ma non sono riuscito a trovare un modo per risolvere il mio problema.

+3

dare uno sguardo qui per una buona monade tutorial: http://blog.sigfpe.com/2006/ 08/you-could-have-invented-monads-and.html –

+1

Altre buone risorse possono essere trovate qui in SO. Guarda la sezione relativa, a destra sullo schermo. –

risposta

37

È possibile scrivere in modo semplice una funzione che chiama l'azione readFile e passa il risultato alla funzione di 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])] 
+3

È solo una piccola frase: "la monade IO tinge tutto ciò che la usa". Ho pensato che fosse così, ma è bello vederlo confermato ora. Grazie ^^ – drumfire

15

Beh, non è possibile sbarazzarsi della parte monade IO di IO String. Ciò significa che dovrai rendere la tua funzione restituita IO [(String, [Integer])].

vi consiglio di imparare di più su monadi, ma per ora si può ottenere via con la funzione liftM:

liftM index (readFile "input.txt") 

liftM ha questa firma:

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

Ci vuole una funzione non monadica e lo trasforma in una funzione monadica.

27

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

Haskell ha la nozione di purezza funzionale. Ciò significa che una funzione restituirà sempre lo stesso risultato quando viene chiamata con gli stessi parametri. Il posto solo dove è consentito IO è all'interno della 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 noi don Non voglio perdere, dato che permette al compilatore di riordinare e inline le funzioni molto più liberamente, possono essere innescate in diversi core senza cambiare la semantica e dà anche ai programmatori un senso di sicurezza poiché se si può ora che cosa una funzione può e non può fare dal suo tipo.

* Attualmente in questo caso è tale funzione. Si chiama unsafePerformIO e si chiama così per molto, molto buoni motivi. Non usarlo se non sei sicuro al 100% di quello che stai facendo!

+13

direi "Non usarlo se non sei sicuro al 200% di quello che stai facendo" o, ancora più semplice, "Non farlo". –

+6

Direi che l'uso migliore di unsafePerformIO è quello di eseguire lo shell out di un processo che dovrebbe sempre restituire la stessa cosa. cioè un calcolo di sistema non supportato nativamente dalla libreria standard. – alternative

+4

Aggiungendo al mio vecchio commento che ho appena trovato durante la navigazione SO: Utile anche per FFI – alternative

8
fmap index $ readFile "input.txt" 

o

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

Si consiglia di guardare in monade e funtori