Lectura de archivos Haskell
Recientemente he comenzado a aprender Haskell y estoy teniendo muchos problemas tratando de averiguar cómo funciona la lectura de archivos.
Por ejemplo, tengo un archivo de texto "test.txt" Y contiene líneas de números por ejemplo:
32 4
2 30
300 5
Quiero leer cada línea y luego evaluar cada palabra y agregarlas. Así que estoy tratando de hacer algo como esto hasta ahora:
import System.IO
import Control.Monad
main = do
let list = []
handle <- openFile "test.txt" ReadMode
contents <- hGetContents handle
singlewords <- (words contents)
list <- f singlewords
print list
hClose handle
f :: [String] -> [Int]
f = map read
Sé que esto es completamente incorrecto, pero no se como usar la sintaxis correctamente. Cualquier ayuda será en gran medida apreciar. Así como enlaces a buenos tutoriales que tienen ejemplos y explicación de código excepto este: http://learnyouahaskell.com/input-and-output lo he leído completamente
3 answers
No es un mal comienzo! Lo único que hay que recordar es que la aplicación pure function debe usar let
en lugar del enlace <-
.
import System.IO
import Control.Monad
main = do
let list = []
handle <- openFile "test.txt" ReadMode
contents <- hGetContents handle
let singlewords = words contents
list = f singlewords
print list
hClose handle
f :: [String] -> [Int]
f = map read
Este es el cambio mínimo necesario para que la cosa se compile y ejecute. Estilísticamente, tengo algunos comentarios:
- La unión
list
dos veces parece un poco sombría. Tenga en cuenta que esto no está mutando el valorlist
's sino que está sombreando la definición antigua. - Funciones puras en línea mucho más!
- Cuando sea posible, usar
readFile
es es preferible abrir, leer y cerrar un archivo manualmente.
La implementación de estos cambios da algo como esto:
main = do
contents <- readFile "test.txt"
print . map readInt . words $ contents
-- alternately, main = print . map readInt . words =<< readFile "test.txt"
readInt :: String -> Int
readInt = read
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
2011-10-23 17:21:40
La solución de Daniel Wagner es excelente. Aquí hay otro giro para que pueda obtener más ideas sobre el manejo eficiente de archivos.
{-# LANGUAGE OverloadedStrings #-}
import System.IO
import qualified Data.ByteString.Lazy.Char8 as B
import Control.Applicative
import Data.List
sumNums :: B.ByteString -> Int
sumNums s = foldl' sumStrs 0 $ B.split ' ' s
sumStrs :: Int -> B.ByteString -> Int
sumStrs m i = m+int
where Just(int,_) = B.readInt i
main = do
sums <- map sumNums <$> B.lines <$> B.readFile "testy"
print sums
Primero, verás el pragma OverloadedStrings. Esto permite usar comillas normales para literales de cadena que son en realidad bytestrings. Usaremos Lazy ByteStrings para procesar el archivo por varias razones. Primero, nos permite transmitir el archivo a través del programa en lugar de forzarlo todo a la memoria a la vez. También, las bytestrings son más rápidas y eficientes que las cadenas en general.
Todo lo demás es bastante sencillo. Leemos el archivo en una lista perezosa de líneas, y luego asignamos una función de suma sobre cada una de las líneas. Los <$>
son solo atajos que nos permiten operar en el valor dentro del funtor IO() if si esto es demasiado, me disculpo. Solo quiero decir que cuando usted readFile usted no consigue detrás un ByteString, usted consigue detrás un ByteString envuelto en IO un IO (ByteString). El <$>
dice "Hey' Quiero operar la cosa dentro del IO y luego envolverlo de nuevo.
B. split separa cada línea en números basados en espacios en blanco. (También podríamos usar B. words para esto) La única otra parte interesante es la in sumStrs
usamos deconstrucción/coincidencia de patrones para extraer el primer valor del Solo que es devuelto por la función readInt.
Espero que esto haya sido útil. Pregunte si tiene alguna pregunta.
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
2011-10-23 17:32:12
Para todos los programadores no funcionales que hay aquí es una delicia
unsafePerformIO . readFile $ "file.txt"
Lee un archivo en una cadena
No hay cadena IO, solo una cadena normal completamente cargada lista para usar. Esto puede no ser la manera correcta, pero funciona y no es necesario cambiar sus funciones existentes para adaptarse a IO String
P. S. No te olvides de importar
import System.IO.Unsafe
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-06-23 21:01:50