Подтвердить что ты не робот

Чтение файла Haskell

Недавно я начал изучать Haskell, и у меня много проблем, пытаясь понять, как работает чтение файла.

Например, у меня есть текстовый файл test.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 Я прочитал его полностью

4b9b3361

Ответ 1

Неплохое начало! Единственное, что нужно помнить, это то, что приложение чистой функции должно использовать 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

Ответ 2

Решение Daniel Wagner - отличное решение. Вот еще один поворот в нем, чтобы вы могли получить больше идей об эффективной обработке файлов.

{-#  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. Это позволяет использовать обычные кавычки для строковых литералов, которые фактически являются байтами. Мы будем использовать Lazy ByteStrings для обработки файла по нескольким причинам. Во-первых, это позволяет нам передавать файл через программу, а не сразу заставлять все это в памяти. Кроме того, bytestrings быстрее и эффективнее, чем строки в целом.

Все остальное довольно просто. Мы читаем файл в ленивый список строк, а затем сопоставляем функцию суммирования по каждой из строк. <$> - это просто ярлыки, позволяющие нам управлять значением внутри функтора IO() - если это слишком много, я приношу свои извинения. Я просто имею в виду, что когда вы читаетеFile, вы не возвращаете ByteString, вы возвращаете ByteString, завернутый в IO IO (ByteString). <$> говорит: "Эй, я хочу работать с вещью внутри IO, а затем завернуть ее обратно.

B.split разделяет каждую строку на числа, основанные на пробеле. (Мы могли бы также использовать B.words для этого). Еще одна интересная часть - это в sumStrs мы используем сопоставление деконструкции/шаблона для извлечения первого значения из Just, которое возвращается функцией readInt.

Надеюсь, это было полезно. Спросите, есть ли у вас какие-либо вопросы.

Ответ 3

Для всех вас неработающие программисты здесь - это удовольствие

unsafePerformIO . readFile $ "file.txt"

Считывает файл в строку

No IO String, просто нормальная полностью загруженная строка готова для использования. Это может быть неправильным, но это работает, и нет необходимости изменять существующие функции в соответствии с IO String

p.s. Не забывайте импортировать

import System.IO.Unsafe