Чтение файла Haskell
Я только недавно начал изучать Haskell, и у меня есть много проблем, пытаясь выяснить, как работает чтение файлов.
например, у меня есть текстовый файл".формат txt" И он содержит строки чисел, например:
32 4
2 30
300 5
Я хочу прочитать каждую строку, а затем оценить каждое слово и добавить их. Таким образом я пытаюсь сделать что-то подобное до сих пор:
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
Я знаю, что это совершенно неправильно, но я не знаю, как правильно использовать синтаксис все. Любая помощь будет очень признательна. А также ссылки на хорошие учебники, которые имеют примеры и объяснение кода, кроме этого: http://learnyouahaskell.com/input-and-output я прочитал его полностью
3 ответов
неплохое начало! Единственное, что нужно помнить, что приложение pure function должно использовать let
вместо привязки <-
.
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
это минимальное изменение, необходимое, чтобы получить вещь для компиляции и запуска. Стилистически, у меня есть несколько комментариев:
- обязательные
list
в два раза выглядит немного подозрительно. Обратите внимание, что это не изменяет значениеlist
-- вместо этого он затеняет старое определение. - встроенные чистые функции много еще!
- по возможности, используя
readFile
предпочтительнее, чем открывать, читать и закрывать файл вручную.
реализация этих изменений дает что-то вроде этого:
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
решение Даниэля Вагнера-отличное. Вот еще один поворот, чтобы вы могли получить больше идей об эффективной обработке файлов.
{-# 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
во-первых, вы увидите OverloadedStrings ПРАГМА. Это позволяет использовать только обычные кавычки для строковых литералов, которые на самом деле являются bytestrings. Мы будем использовать Lazy ByteStrings для обработки файла по нескольким причинам. Во-первых, это позволяет нам передавать файл через программу, а не заставлять все это в память сразу. Кроме того, bytestrings быстрее и эффективнее, чем строки в целом.
все остальное довольно просто. Мы readFile файл в ленивый список строк, а затем сопоставить функцию суммирования над каждой из строк. The <$>
- это просто ярлыки, позволяющие нам работать со значением внутри функтора IO () - если это слишком много, я прошу прощения. Я просто имею в виду, что когда вы читаете файл, вы не получаете ByteString, вы получаете ByteString, завернутый в IO AN IO(ByteString). The <$>
говорит: "Эй, я хочу оперировать вещь внутри IO, а затем обернуть ее обратно.
B. split разделяет каждую строку на числа на основе пробелов. (Мы также могли бы использовать B. слова для этого) единственная другая интересная часть-in sumStrs
мы используем deconstruction / pattern matching для извлечения первого значения из Только что возвращенного функцией readInt.
Я надеюсь, это было полезно. Спрашивайте, если у вас есть вопросы.
для всех вас, нефункциональных программистов, здесь есть удовольствие
unsafePerformIO . readFile $ "file.txt"
считывает файл в строку
нет строки ввода-вывода, просто обычная полностью загруженная строка готова к использованию. Это может быть неправильным способом, но он работает, и нет необходимости изменять существующие функции в соответствии со строкой ввода-вывода
п.С. Не забудьте импортировать
import System.IO.Unsafe