1

I currently have a 2D array declared as:

import Data.Array.Unboxed
listArray ((0,0), (9,9)) (replicate 100 'f') ∷  UArray (Int, Int) Char

I am trying to set a value in this array from a set of coordinates, (x, y) stored as a tuple, changing the value into a t, instead of an f. I have fooled around with lenses, however, I have had no success with them.

Any help is appreciated!

  • You probably want to look at the `Ixed` class in [`Control.Lens.At`](https://hackage.haskell.org/package/lens-4.13/docs/Control-Lens-At.html). – dfeuer Oct 13 '15 at 03:09
  • Thanks, I'll look at it right now –  Oct 13 '15 at 03:10
  • It appears that Control.Lens.At is used for Lists, not Arrays unfortunately –  Oct 13 '15 at 03:14
  • it can be used for lots of things, but you need `Ixed`, which can be used for even more. – dfeuer Oct 13 '15 at 03:17
  • The examples in the documentation may show lists, but there are many other instances, including for arrays. Look at the instance list right under the class definition. – dfeuer Oct 13 '15 at 03:18
  • Related, but perhaps more depth than necessary: http://stackoverflow.com/questions/18414177/what-is-the-difference-between-ix-and-at-in-the-lens-library-of-haskell – dfeuer Oct 13 '15 at 05:42

2 Answers2

1

The simplest update function for arrays is (//), which has this type:

(//) :: (IArray a e, Ix i) => a i e -> [(i, e)] -> a i e 

For example:

Data.Array.Unboxed> listArray (0, 4) "abcde" // [(1, 'f')] :: UArray Int Char
array (0,4) [(0,'a'),(1,'f'),(2,'c'),(3,'d'),(4,'e')]

You can access particular elements with (!):

Data.Array.Unboxed> it ! 1
'f'
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
0

To access individual elements of an array with lens, you need to use the ix method of the Ixed class, defined in Control.Lens.At. If you define

fooArray :: UArray (Int, Int) Char
fooArray = listArray ((0,0), (9,9)) (replicate 100 'f')

then, firing up GHCi,

> fooArray ^? ix (1,2)
Just 'f'
> let fooArray' = fooArray & ix (1,2) .~ 't'
> fooArray' ^? ix (1,2)
Just 't'

Note that editing arrays like this is pretty inefficient if the arrays are large; if you need high speed or lots of array edits, you may want to consider a different structure.

The easiest ways to smash an array flat are the elems function from Data.Array.Unboxed or toList from Data.Foldable. If what those give you is sideways, you can probably patch it up with ixmap.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
  • Unfortunately, I get `Not in scope: ^?` `Perhaps you meant one of these:` `^ (imported from Prelude), ^^ (imported from Prelude)` From that statement –  Oct 13 '15 at 05:35
  • @anon, that's defined elsewhere; you'll get that *and* `Ixed` if you import `Control.Lens`. – dfeuer Oct 13 '15 at 05:44
  • Final error (I hope) `parse error in let binding: missing required "in"` I believe this is simply because I am doing something stupid with binding the value using `let` –  Oct 13 '15 at 05:50
  • @anon, that was part of a GHCi session, which handles `let` differently. In a module, you'd just write `fooArray' = fooArray & ix (1,2) .~ 't'` (preferably with a type signature above it), and leave out the `let`. – dfeuer Oct 13 '15 at 05:53
  • That fixed it, thanks so much for your time and patients! –  Oct 13 '15 at 05:57