【问题标题】:Reading from input files in haskell从haskell中的输入文件读取
【发布时间】:2012-04-02 15:47:05
【问题描述】:

我正在解决Project Euler Problem 11。我已将问题中的表格复制粘贴到名为“input.txt”的文件中。输入文件的每一行包含一行 20x20 矩阵,列之间用空格分隔。

我想要的是一个读取这个文件并将它作为一个 IO 数组返回的函数。我在这样做时遇到了很大的麻烦。

到目前为止,我已经这样做了:

import System.IO
import Control.Monad

main = readFile "input.txt"

这当然只给了我输入文件的 IO 字符串表示,但我尝试的一切似乎都失败了。我应该如何进行?我知道我应该做类似的事情

array ((1,1),(20,20)) [ the numbers tupled with their indices ]

但是对我来说转换数字是完全不可能的,很可能是因为我还没有完全理解单子。

我相信这实际上很容易,一旦你理解了它。

有没有人有什么建议?

【问题讨论】:

  • input.txt的格式是什么?
  • 什么意思?这是一个 txt 文件,我只是将矩阵复制粘贴到其中。
  • @Undreren:告诉人们“input.txt”的格式是什么很重要。我的意思是,它可能是莎士比亚的全集,它可能在每条奇数行上有一个浮点数,在每条偶数行上有一只猫的名字,或者像你的情况一样,它可能包含 20 行和 20每个以空格分隔的整数。我只是在阅读您要解决的问题时才发现这一点——这应该是问题所在。
  • 好的,我只是认为链接到矩阵更整洁,因为它占用了太多空间。
  • 有点离题:可能要考虑使用优秀的vector

标签: arrays haskell io


【解决方案1】:

你可以用这样的方式解析你的文件:

s = "2 4\n6 8"

s' :: [Int]
s' = (map read . words) s

let arr = listArray ((1,1),(2,2)) s'
-- arr == array ((1,1),(2,2)) [((1,1),2),((1,2),4),((2,1),6),((2,2),8)]

通过将wordsmap read(其中read :: (Read a) => String -> a)结合起来,您将得到一个[Int] 列表。

因此,为了稍微组织一下,您在 IO monad 中的代码可能如下所示(假设每一行都有相同的固定列数,并且您获取输入文件名、行数和列作为命令行参数):

module Main

where

import Data.Array
import Control.Monad
import System.Environment

readWords :: (Read a) => String -> [a]
readWords = map read . words

parseFile :: String -> Int -> Int -> IO (Array (Int, Int) Int)
parseFile fname rows cols = do
    matr <- liftM readWords $ readFile fname
    return $ listArray ((1, 1), (rows, cols)) matr
    -- (matr :: [Int] is inferred from the parseFile's type)

main :: IO ()
main = do
    args <- getArgs
    case args of
        [fname, rows, cols] -> do
            arr <- parseFile fname (read rows) (read cols)
            print arr

请注意转换函数readWords 是如何能够转换为任何[a] 的,前提是Read a,这样我们就不会仅限于整数。 liftM 函数采用纯函数(我们的 readWords)并“提升”它以在当前 monad 中工作,即 IO

【讨论】:

  • 对于给定的格式,一个简单的map read . words 就足够了,在这种情况下,没有理由将它分成几行和最后的concat。当然,将输入分成几行通常是更有用的方法。
  • @DanielFischer:哈哈,你是对的,我将在答案中更正它。谢谢你:)
【解决方案2】:

整个程序应该是这样的:

import System.IO
import Data.Array

main = do
    content <- readFile "input.txt"
    let matrix = map (map read . words) $ lines content     -- [[Int]]
    let arr = listArray ((1, 1), (20, 20)) (concat matrix)
    putStr $ solve arr

其中solveArray (Int, Int) Int -&gt; String类型的函数。

【讨论】:

  • 这甚至不会编译?我删除了putStrsolve 部分以测试它是否有效,但它没有。
  • 我猜问题出在read 的类型推断上。尝试强制 let matrix[[Int]] 类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
相关资源
最近更新 更多