43 | | (Ix (Shape dim), U.Elt a) => Array dim a |
44 | | |
45 | | }}} |
46 | | where Ix is the standard Haskell index class, Shape is a type family defined on tuples of integers, including nullary |
47 | | tuples - arrays of which correspond to scalar values. So, for example |
48 | | {{{ |
49 | | Array () Double -- scalar double precision floating point value |
50 | | Array (Int,Int) Double -- two dimensional array (matrix) |
51 | | }}} |
52 | | `U.Elt` is the `Elt` type class defined in ` Data.Array.Parallel.Unlifted` and contains all primitive types like `Int`, `Bool`, and tuples thereof. |
53 | | |
54 | | |
55 | | Internally, shapes are represented as nested pairs |
56 | | {{{ |
57 | | type family Shape dim |
58 | | type instance Shape () = () |
59 | | type instance Shape (Int) = ((),Int) |
60 | | type instance Shape (Int, Int) = (((),Int), Int) |
61 | | }}} |
62 | | The user, however, doesn't need to be aware of this and can view the shape of an n-dimensional array as n-tuple of integer values. |
63 | | |
64 | | For readability, we define the following type synonyms: |
65 | | {{{ |
66 | | type DIM0 = Shape () |
67 | | type DIM1 = Shape Int |
68 | | type DIM2 = Shape (Int, Int) |
69 | | type DIM3 = Shape (Int, Int, Int) |
| 43 | (Shape dim, U.Elt a) => Array dim a |
| 44 | }}} |
| 45 | The element type of multidimensional arrays is restricted to the type class `Elt` exported from ` Data.Array.Parallel.Unlifted`, and contains all primitive types like `Bool`, `Int`, `Float`, and pairs thereof constructed with the type constructor `:*:`, also exported from the same module. The elements of the type class `Shape` describe the shape of a multidimensional array, but also indices into |
| 46 | an array ('''Note:''' so, is `Shape` really the right name? `Ix` however, also doesn't seem to be right, since it is too different from the`Ix` defined in the Prelude) |
| 47 | {{{ |
| 48 | class U.Elt sh => Shape sh where |
| 49 | dim :: sh -> Int -- number of dimensions (>= 0) |
| 50 | size :: sh -> Int -- for a shape, yield the total number of |
| 51 | -- elements in that array |
| 52 | index :: sh -> sh -> Int -- corresponding index into a linear, row-major |
| 53 | -- representation of the array (first argument |
| 54 | -- is the shape) |
| 55 | |
| 56 | shLast:: (sh :*: Int) -> Int -- given an at least one dimensional shape, returns the innermost |
| 57 | -- dimension |
| 58 | shInit:: (sh :*: Int) -> sh -- returns the outermost dimensions |
| 59 | range:: sh -> U.Array sh -- all indexes for a given shape |
| 60 | }}} |
| 61 | |
| 62 | with the following instances: |
| 63 | |
| 64 | {{{ |
| 65 | instance Shape () |
| 66 | instance (Shape sh1, U.Elt sh1) => Shape (sh1 :*: Int) |
| 67 | }}} |
| 68 | So, for example a two dimensional array of three vectors of the length five has the shape `(() :*: 5) :*: 3`. This is a suitable internal representation, but it should be hidden from the user, who should be provided with a more familiar notation, but for now, we will stick with the internal representation. |
| 69 | |
| 70 | We use the following type synonyms to improve the readability of the code: |
| 71 | {{{ |
| 72 | type DIM0 = () |
| 73 | type DIM1 = DIM0 :*: Int |
| 74 | type DIM2 = DIM1 :*: Int |
| 75 | type DIM3 = DIM2 :*: Int |