Вы можете проанализировать ваш файл примерно так:
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]
.
Итак, чтобы немного упорядочить вещи, ваш код в монаде ввода-вывода может выглядеть следующим образом (при условии, что каждая строка имеет одинаковое фиксированное число столбцов и что вы берете имя входного файла, количество строк и столбцов в качестве аргументов командной строки):
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
) и «поднимает» ее для работы в текущей монаде, т.е. IO
.