2009-11-04 17 views
31

Escribí un montón de código en Haskell para crear un índice de un texto. La función de la parte superior se ve así:Una función de tipo Haskell: IO String-> String

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

Ahora me quieren dar esta función una cadena leer desde un archivo:

index readFile "input.txt" 

que no funcionará porque readFile es de tipo FilePath -> IO Cadena .

no pudo igualar esperada tipo 'Cadena' contra el tipo inferido 'IO Cadena'

veo el error, pero no puedo encontrar ninguna función con el tipo:

IO String -> String 

Supongo que la clave del éxito está en algún lugar debajo de algunas Mónadas, pero no pude encontrar una manera de resolver mi problema.

+3

Echa un vistazo aquí para un buen tutorial mónada: http://blog.sigfpe.com/2006/ 08/you-could-have-invent-monads-and.html –

+1

Otros buenos recursos se pueden encontrar aquí en SO. Simplemente mira la sección relacionada, hacia la derecha en tu pantalla. –

Respuesta

37

Puede escribir fácilmente una función que llame a la acción readFile y pasa el resultado a su función de índice.

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

Sin embargo, la mónada IO contamina todo lo que lo utiliza, por lo que esta función tiene el tipo:

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

Es solo una pequeña oración: "la món IO contamina todo lo que la usa". Asumí que este era el caso, pero es bueno verlo confirmado ahora. Gracias ^^ – drumfire

15

bien que no puede deshacerse de la parte IO mónada de IO String. Eso significa que tendrá que hacer que su función devuelva IO [(String, [Integer])].

recomiendo aprender más acerca de las mónadas, pero por ahora se puede salirse con la función liftM:

liftM index (readFile "input.txt") 

liftM tiene esta firma:

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

Se necesita una función no monádico y lo transforma en una función monádica.

27

Hay una muy buena razón por la que no hay tal función.

Haskell tiene la noción de pureza funcional. Esto significa que una función siempre devolverá el mismo resultado cuando se invoque con los mismos parámetros. El único lugar donde está permitido IO está dentro de la mónada IO.

Si hubo * una función

index :: IO String -> String 

entonces podríamos repente hacer acciones IO en cualquier lugar llamando, por ejemplo:

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

pureza funcional es una característica muy útil que Don No quiero perder, ya que permite al compilador reordenar y alinear las funciones mucho más libremente, pueden activarse en diferentes núcleos sin cambiar la semántica y también les da a los programadores una sensación de seguridad, ya que si puedes k ahora qué función puede y qué no puede hacer su tipo.

* En realidad existe es tal función. Se llama unsafePerformIO y se llama así por muy, muy buenas razones. ¡No lo use a menos que esté 100% seguro de lo que está haciendo!

+13

Iría tan lejos como diciendo "No lo use a menos que esté 200% seguro de lo que está haciendo" o, incluso más simple, "No lo haga". –

+6

Diría que el mejor uso para inseguroPerformIO es pagar un proceso que siempre debería devolver lo mismo. es decir, un cálculo del sistema no soportado nativamente por la biblioteca estándar. – alternative

+4

Agregando a mi viejo comentario que acabo de encontrar al navegar alrededor de SO: También es útil para FFI – alternative

8
fmap index $ readFile "input.txt" 

o

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

Es posible que desee ver en la mónada y funtores