I'm trying to learn the proper syntax for arrays in Haskell (I know, not the most used construct in Haskell but I want to learn how to use them for when I need it). I'm trying for now to just reverse the elements in the array, using the "//" operator (all from GHC.arr).
The relevant code is as follow:
test = listArray (1,4) [1..4]
reverser x = x//[(i, x!j) | i<-[1..4], j<-[4,3..1]]
This results in: array (1,4) [(1,1),(2,1),(3,1),(4,1)]
, and I really don't get why. Looking at the first entry in the new array, I would expect (1, x!4) = (1, 4).
Because at some point I will need to reverse selected parts of the array, including single elements, I also tried:
reverser x = x//[(i, x!j) | i<-[1..4], j<-enumFromTo 4 1]
This resulted in: array (1,4) [(1,1),(2,2),(3,3),(4,4)]
: I thought [4,3..1] was just syntaxic sugar for enumFromTo 4 1, so not only don't I understand the result, I don't see why it is different from the previous one.
Try taking a look at just the update part, and you'll see what's going on immediately:
> x = listArray (1,4) [1..4]
> [(i, x!j) | i<-[1..4], j<-[4,3..1]]
[(1,4),(1,3),(1,2),(1,1),(2,4),(2,3),(2,2),(2,1),(3,4),(3,3),(3,2),(3,1),(4,4),(4,3),(4,2),(4,1)]
Whoops! I wager that update list is a bit longer than you expected. In a list comprehension, ,
means a nested loop, not a parallel loop. You could turn on fancy list comprehensions and use a second |
:
> :set -XParallelListComp
> -- v
> [(i, x!j) | i<-[1..4] | j<-[4,3..1]]
[(1,4),(2,3),(3,2),(4,1)]
Or you could use zipWith
without any additional extensions:
> zipWith (\i j -> (i, x!j)) [1..4] [4,3..1]
[(1,4),(2,3),(3,2),(4,1)]
But probably the best solution is to use ixmap
, which was made for this, and doesn't require creating any intermediate lists:
> ixmap (1,4) (5-) x
array (1,4) [(1,4),(2,3),(3,2),(4,1)]