我正在解决Project Euler Problem 11。我已将问题中的表复制粘贴到名为“input.txt”的文件中。输入文件的每一行包含一行20x20矩阵,列用空格分隔。
我想要的是一个读取此文件的函数,并将其作为IO数组返回。我在这方面遇到了很大麻烦。
到目前为止,我已经这样做了:
import System.IO
import Control.Monad
main = readFile "input.txt"
这当然只给我输入文件的IO String表示,但我尝试的一切似乎都失败了。我该怎么办?我知道我应该做点什么
array ((1,1),(20,20)) [ the numbers tupled with their indices ]
但转换这些数字对我来说是完全不可能的,很可能是因为我还没有完全理解monad。
我相信,一旦你明白这一点,这实际上很容易。
有没有人建议做什么?
答案 0 :(得分:5)
您可以使用以下内容解析文件:
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)]
将words
与map 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
)和&#34;提升&#34;它适用于当前的monad,即IO
。
答案 1 :(得分:0)
整个程序应该是这样的:
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
其中solve
是Array (Int, Int) Int -> String
类型的函数。