Haskell 文件读取

发布于 2024-12-11 11:24:54 字数 704 浏览 1 评论 0原文

我最近刚刚开始学习 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

我知道这是完全错误的,但我根本不知道如何正确使用语法。

任何帮助以及包含示例和代码解释的优秀教程的链接将不胜感激,除了这个 我已完整阅读。

I have just recently started learning Haskell and I am having a lot of trouble trying to figure out how file reading works.

For example, I have a text file "test.txt" containing lines with numbers:

32 4
2 30
300 5

I want to read each line and then evaluate each word and add them.

Thus, I am trying to do something like this:

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

I know this is completely wrong, but I don't know how to use the syntax correctly at all.

Any help will be greatly appreciated as well as links to good tutorials that have examples and explanation of code except this one which I have read fully.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我不咬妳我踢妳 2024-12-18 11:24:54

不错的开始!唯一要记住的是纯函数应用程序应该使用 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

Not a bad start! The only thing to remember is that pure function application should use let instead of the binding <-.

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

This is the minimal change needed to get the thing to compile and run. Stylistically, I have a few comments:

  1. Binding list twice looks a bit shady. Note that this isn't mutating the value list -- it's instead shadowing the old definition.
  2. Inline pure functions a lot more!
  3. When possible, using readFile is preferable to manually opening, reading, and closing a file.

Implementing these changes gives something like this:

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
猫卆 2024-12-18 11:24:54

丹尼尔·瓦格纳的解决方案是一个很好的解决方案。这是另一个方面,以便您可以获得有关高效文件处理的更多想法。

{-#  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 <
gt; B.lines <
gt; B.readFile "testy"
  print sums

首先,您将看到 OverloadedStrings 编译指示。这允许用户仅对实际上是字节串的字符串文字使用普通引号。出于多种原因,我们将使用 Lazy ByteStrings 来处理文件。首先,它允许我们通过程序流式传输文件,而不是将其全部强制一次放入内存中。此外,字节串通常比字符串更快、更高效。

其他一切都非常简单。我们将文件读入一个惰性行列表中,然后在每行上映射一个求和函数。 <$> 只是允许我们对 IO() 函子内部的值进行操作的快捷方式——如果这太多了,我深表歉意。我只是说,当你 readFile 时,你不会返回一个 ByteString,而是返回一个 IO 和 IO(ByteString) 中包裹的 ByteString。 <$> 表示“嘿”我想对 IO 内部的内容进行操作,然后将其包装回去。B.split

根据空格将每一行分成数字。(我们也可以使用 B.words )唯一有趣的部分是在 sumStrs 中,我们使用解构/模式匹配从 readInt 函数返回的 Just 中提取第一个值,

我希望这是这样 。询问有帮助。 如有任何问题。

Daniel Wagner's solution is a great one. Here is another swing at it so you can get some more ideas about efficient file handling.

{-#  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 <
gt; B.lines <
gt; B.readFile "testy"
  print sums

First, you'll see the OverloadedStrings pragma. This allows use to just use normal quotes for string literals that are actually bytestrings. We will be using Lazy ByteStrings for processing the file for several reasons. First, it allows us to stream the file through the program rather than forcing it all into memory at once. Also, bytestrings are faster and more efficient than strings in general.

Everything else is pretty much straightforward. We readFile the file into a lazy list of lines, and then map a summing function over each of the lines. The <$> are just shortcuts to allow us to operate on the value inside of IO() functor -- if this is too much I apologize. I just mean that when you readFile you don't get back a ByteString, you get back a ByteString wrapped in IO an IO(ByteString). The <$> says "Hey' I want to operate on the thing inside the IO and then wrap it back up.

B.split separates each line into numbers based on whitespace. (We could also use B.words for this) The only other interesting part is the in sumStrs we use deconstruction/pattern matching to extract the first value out of the Just that is returned by the readInt function.

I hope this was helpful. Ask if you have any questions.

揪着可爱 2024-12-18 11:24:54

对于所有非函数式程序员来说,这里有一种享受:

unsafePerformIO . readFile $ "file.txt"

将文件读入字符串

,没有 IO 字符串,只是一个正常的完全加载的字符串可供使用。
这可能不是正确的方法,但它有效,并且无需更改现有函数以适应 IO 字符串


不要忘记导入

import System.IO.Unsafe 

For all you non-functional programmers out there here is a treat

unsafePerformIO . readFile $ "file.txt"

Reads a file into a string

No IO String, just a normal fully loaded string ready for use.
This might not be the right way but it works and no need to change your existing functions to suit IO String

p.s.
Dont forget to import

import System.IO.Unsafe 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文