1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
<title>The Haskell 98 Library Report: Indexing Operations</title>
<body bgcolor="#ffffff"> <i>The Haskell 98 Library Report</i><br> <a href="index.html">top</a> | <a href="numeric.html">back</a> | <a href="array.html">next</a> | <a href="libindex.html">contents</a> <br><hr>
<a name="sect5"></a>
<h2>5<tt> </tt>Indexing Operations</h2><p>
<table border=2 cellpadding=3>
<tr><td>
<tt><br>
module Ix ( Ix(range, index, inRange), rangeSize ) where<br>
<br>
class (Ord a) => Ix a where<br>
range :: (a,a) -> [a]<br>
index :: (a,a) -> a -> Int<br>
inRange :: (a,a) -> a -> Bool<br>
<br>
rangeSize :: (Ix a) => (a,a) -> Int<br>
<br>
instance Ix Char where ...<br>
instance Ix Int where ...<br>
instance Ix Integer where ...<br>
instance (Ix a, Ix b) => Ix (a,b) where ...<br>
-- et cetera<br>
instance Ix Bool where ...<br>
instance Ix Ordering where ...<br>
</tt></td></tr></table>
The <tt>Ix</tt> class is used to map a continuous subrange of values in a
type onto integers. It is used primarily for array indexing (see
Section <a href="array.html#arrays">6</a>).
The <tt>Ix</tt> class contains the methods <tt>range</tt>,
<tt>index</tt>, and <tt>inRange</tt>.
The <tt>index</tt> operation maps a bounding pair, which defines the lower
and upper bounds of the range, and a
subscript, to an integer. The <tt>range</tt> operation enumerates all
subscripts; the <tt>inRange</tt> operation tells whether a particular subscript
lies in the range defined by a bounding pair.<p>
An implementation is entitled to assume the following laws about these
operations:
<tt><br>
<br>
range (l,u) !! index (l,u) i == i -- when i is in range<br>
<br>
inRange (l,u) i == i `elem` range (l,u)<br>
<br>
<p>
</tt><a name="sect5.1"></a>
<h3>5.1<tt> </tt>Deriving Instances of <tt>Ix</tt></h3><p>
Derived instance declarations for the class <tt>Ix</tt> are only possible
for enumerations (i.e. datatypes having
only nullary constructors) and single-constructor datatypes,
including arbitrarily large tuples, whose constituent types are
instances of <tt>Ix</tt>.
<UL><LI>
For an <I>enumeration</I>, the nullary constructors are assumed to be
numbered left-to-right with the indices being 0 to n-1 inclusive.
This is the same numbering defined by the <tt>Enum</tt> class. For example,
given the datatype:
<tt><br>
<br>
data Colour = Red | Orange | Yellow | Green | Blue | Indigo | Violet<br>
<br>
</tt>we would have:
<tt><br>
<br>
range (Yellow,Blue) == [Yellow,Green,Blue]<br>
index (Yellow,Blue) Green == 1<br>
inRange (Yellow,Blue) Red == False<br>
<br>
</tt><LI>
For <I>single-constructor datatypes</I>, the derived instance declarations
are as shown for tuples in
Figure <a href="ix.html#prelude-index">1</a>.
</UL><p>
<table border=2 cellpadding=3>
<tr><td>
<table border=2 cellpadding=3>
<tr><td>
<tt><br>
instance (Ix a, Ix b) => Ix (a,b) where<br>
range ((l,l'),(u,u'))<br>
= [(i,i') | i <- range (l,u), i' <- range (l',u')]<br>
index ((l,l'),(u,u')) (i,i')<br>
= index (l,u) i * rangeSize (l',u') + index (l',u') i'<br>
inRange ((l,l'),(u,u')) (i,i')<br>
= inRange (l,u) i && inRange (l',u') i'<br>
<br>
-- Instances for other tuples are obtained from this scheme:<br>
--<br>
-- instance (Ix a1, Ix a2, ... , Ix ak) => Ix (a1,a2,...,ak) where<br>
-- range ((l1,l2,...,lk),(u1,u2,...,uk)) =<br>
-- [(i1,i2,...,ik) | i1 <- range (l1,u1),<br>
-- i2 <- range (l2,u2),<br>
-- ...<br>
-- ik <- range (lk,uk)]<br>
--<br>
-- index ((l1,l2,...,lk),(u1,u2,...,uk)) (i1,i2,...,ik) =<br>
-- index (lk,uk) ik + rangeSize (lk,uk) * (<br>
-- index (lk-1,uk-1) ik-1 + rangeSize (lk-1,uk-1) * (<br>
-- ...<br>
-- index (l1,u1)))<br>
--<br>
-- inRange ((l1,l2,...lk),(u1,u2,...,uk)) (i1,i2,...,ik) =<br>
-- inRange (l1,u1) i1 && inRange (l2,u2) i2 &&<br>
-- ... && inRange (lk,uk) ik<br>
</tt></td></tr></table>
<div align=center><h3>Derivation of Ix instances</h3></div><a name="prelude-index"></a>
</td></tr></table>
<p>
<a name="sect5.2"></a>
<h3>5.2<tt> </tt>Library <tt>Ix</tt></h3>
<tt><br>
module Ix ( Ix(range, index, inRange), rangeSize ) where<br>
<br>
class (Ord a) => Ix a where<br>
range :: (a,a) -> [a]<br>
index :: (a,a) -> a -> Int<br>
inRange :: (a,a) -> a -> Bool<br>
<br>
rangeSize :: Ix a => (a,a) -> Int<br>
rangeSize b@(l,h) | null (range b) = 0<br>
| otherwise = index b h + 1 <br>
-- NB: replacing "null (range b)" by "l > h" fails if<br>
-- the bounds are tuples. For example,<br>
-- (2,1) > (1,2), <br>
-- but <br>
-- range ((2,1),(1,2)) = []<br>
<br>
<br>
instance Ix Char where<br>
range (m,n) = [m..n]<br>
index b@(c,c') ci<br>
| inRange b ci = fromEnum ci - fromEnum c<br>
| otherwise = error "Ix.index: Index out of range."<br>
inRange (c,c') i = c <= i && i <= c'<br>
<br>
instance Ix Int where<br>
range (m,n) = [m..n]<br>
index b@(m,n) i<br>
| inRange b i = i - m<br>
| otherwise = error "Ix.index: Index out of range."<br>
inRange (m,n) i = m <= i && i <= n<br>
<br>
instance Ix Integer where<br>
range (m,n) = [m..n]<br>
index b@(m,n) i<br>
| inRange b i = fromInteger (i - m)<br>
| otherwise = error "Ix.index: Index out of range."<br>
inRange (m,n) i = m <= i && i <= n<br>
<br>
instance (Ix a,Ix b) => Ix (a, b) -- as derived, for all tuples<br>
instance Ix Bool -- as derived<br>
instance Ix Ordering -- as derived<br>
instance Ix () -- as derived<br>
<p>
<hr><i>The Haskell 98 Library Report</i><br><a href="index.html">top</a> | <a href="numeric.html">back</a> | <a href="array.html">next</a> | <a href="libindex.html">contents</a> <br><font size=2>1 February, 1999</font>
</tt>
|