Una función Haskell de tipo: IO String - > String


Escribí un montón de código en Haskell para crear un índice de un texto. La función top se ve así:

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

Ahora quiero darle a esta función una cadena leída desde un archivo:

index readFile "input.txt"

Que no funcionará porque readFile es de tipo FilePath -> IO String.

No Podía coincidir con el tipo esperado 'Cadena' contra el tipo inferido 'IO String'

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

IO String -> String

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

Author: R. Martinho Fernandes, 2009-11-04

4 answers

Puede escribir fácilmente una función que llame a la acción readFile y pase el resultado a su función index.

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

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

readAndIndex :: FilePath -> IO [(String, [Integer])]
 39
Author: cthulahoops,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-04 18:13:40

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

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

Si había* una función

index :: IO String -> String

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

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

La pureza funcional es una característica muy útil que no quiero perder, ya que permite al compilador reordenar y funciones en línea mucho más libremente, pueden ser activadas a diferentes núcleos sin cambiar la semántica y también da a los programadores una sensación de seguridad ya que si se puede saber lo que una función puede y no puede hacer desde su tipo.

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

 27
Author: Tirpen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-05 04:26:07

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

Recomiendo aprender más sobre mónadas, pero por ahora puedes salirte con la tuya con la función liftM:

liftM index (readFile "input.txt")

liftM tiene esta firma:

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

Toma una función no monádica y la transforma en una función monádica.

 15
Author: R. Martinho Fernandes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-26 19:24:24
fmap index $ readFile "input.txt"

O

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

Es posible que desee mirar en mónada y funtores

 8
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-05 03:20:55