Conventional wisdom crudely expressed: never use Prelude.foldl
; use foldl'
with a strict accumulator, otherwise foldr
.
There are two questions, I think, one his how to parse the incoming String or ByteString or whatever; the other is what sort of structure to read it into. Of course these aren't completely independent, but I wonder if you couldn't separate concerns a bit more. As I guess you would know, a really barbaric Prelude
way of getting a String
into the right shape might be like so:
parseAsLists :: String -> ((Int,Int), [[Int]])
parseAsLists = start . lines where
start (x:xs) = (size (words x), rows xs)
size (x:y:_) = (read x, read y) :: (Int,Int)
rows ls = map row ls
row l = map read (words l)
main = do str <- getContents
print $ parseAsLists str
-- $ cat linep.txt | runhaskell lineparser.hs
-- ((2,3),[[1,2,3],[4,5,6]])
We divide the string into lines; the first line (assumed to exist!) is divided into numerals, the first two (assumed to exist!) are read (assumed readable!) and returned as a pair; then similarly we make lists of Ints
by reading the words of the succeeding lines.
This is barbaric in a number of ways: it just fails on bad strings; it uses String
instead of Text
or ByteString
; it parses into Haskell lists which are good for some purposes bad for others. The other stringy types have a similar interface, so things would go similarly.
But I think the main trouble was finding a data type to read into? Here I wonder if you might not find the (builtin) array
package natural:
https://hackage.haskell.org/package/array-0.5.0.0/docs/Data-Array.html
Since you are making a finite array of Int
, an unboxed type, you might do well to use the strict, unboxed kind of arrays. The different types have the same interface. For one dimensional arrays, the vector
package is more convenient.
https://hackage.haskell.org/package/array-0.5.0.0/docs/Data-Array-Unboxed.html
We can recycle our crude parseAsLists
as a start:
import Data.Array.Unboxed
parseArraySimple :: String -> UArray (Int,Int) Int
parseArraySimple str = listArray ((0,0),(x',y')) arr
where
((x,y),arrs) = parseAsLists str
(x',y') = (x-1,y-1) -- to use them as indices
arr = concat arrs
Then we could write, say:
main = do str <- readFile "arr.txt"
let arr = parseArraySimple str
loop = do pt <- readLn :: IO (Int,Int)
print $ arr ! pt
loop
loop
With the following highly error prone result:
-- $ ghc -O2 lineparser2.hs
-- $ ./lineparser2
-- Index?
-- (0,0)
-- 1
-- Index?
-- (1,2)
-- 6
-- Index?
-- (20,20)
-- lineparser2.hs: Error in array index