Чтение файла 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

это минимальное изменение, необходимое, чтобы получить вещь для компиляции и запуска. Стилистически, у меня есть несколько комментариев:

  1. обязательные list в два раза выглядит немного подозрительно. Обратите внимание, что это не изменяет значение list -- вместо этого он затеняет старое определение.
  2. встроенные чистые функции много еще!
  3. по возможности, используя 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