While learning Haskell, I was looking for a concise implementation of a function which "reshapes" a list into a matrix. Given the number of rows
r, the number of columns
c, and a list
vs, the function should take
r*c values from the list and create a
r by
c matrix out of them. Here's the type:
toMatrix :: Int -> Int -> [a] -> [[a]]
First solution
First I wrote a simpler function that would split a list into chunks of a given size, like this:
chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf c vs = h : (chunksOf c t)
where (h, t) = splitAt c vs
Using the above,
toMatrix could be implemented this way:
toMatrix r c = chunksOf c . take (r*c)
I had a feeling that a function like
chunksOf should be already present somewhere in the standard library, so I
asked Hoogle, but to no avail. There was
chunksOf in
Data.Text, but it operated on
Text only (I retroactively named my function after the one in
Data.Text). However, Hoogle returned
replicateM as well…
Second solution
… and I realized I could use it with the state monad to implement
toMatrix. The state could contain the list of values yet to be consumed, and the action to be replicated could be chopping off
c values from the list:
splitOnce :: Int -> State [a] [a]
splitOnce c = do
s <- get
let (h, t) = splitAt c s
put t
return h
After a while I realized that the same function could be written in a much more concise form:
splitOnce' :: Int -> State [a] [a]
splitOnce' = state . splitAt
The solution was, therefore:
toMatrix r = evalState . replicateM r . state . splitAt
Summary
The second version is good enough for me and as a bonus it helped me understand the state monad. Note that the two implementations of
toMatrix are
not equivalent, as they handle lists shorter than
r*c in different ways. Future work: find a concise and preferably point-free implementation of
chunksOf.
Update (2013-01-08)
This answer on StackOverflow contains a very nice implementation of
chunksOf.