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 = arrange . map (map read . words) . lines
where arrange ((n:m:_):rows) = ((n,m), rows)
mais = do str <- getContents
print $ parseAsLists str
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
There are several radically different array types with the same interface. The simple Data.Array.Array
type would be fairly close to the lazy ((Int,Int),[[Int]]) type we had, but with e.g. more convenient lookup and so on. Since you are making a finite array of Int
, an unboxed type, you might do well to use the strict, unboxed kind of arrays. (For one dimensional arrays, the vector
package is more convenient; in either case there is a corresponding mutable type.)
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