Описание библиотеки Haskell 98: Операции индексации Описание Haskell 98
наверх | назад | вперед | содержание | предметный указатель функций

15  Операции индексации


module Ix ( Ix(range, index, inRange, rangeSize) ) where

class  Ord a => Ix a  where
    range       :: (a,a) -> [a]
    index       :: (a,a) -> a -> Int
    inRange     :: (a,a) -> a -> Bool
    rangeSize   :: (a,a) -> Int

instance                   Ix Char      where ...
instance                   Ix Int       where ...
instance                   Ix Integer   where ...
instance  (Ix a, Ix b)  => Ix (a,b)     where ...
-- и так далее
instance                   Ix Bool      where ...
instance                   Ix Ordering  where ...

Класс Ix используется для того, чтобы отобразить непрерывный отрезок значений на тип целых чисел. Это используется прежде всего для индексации массивов (см. главу 16). Класс Ix содержит методы range, index и inRange. Операция index отображает пару ограничений, которая определяет нижнюю и верхнюю границы диапазона, и индекс в целое число. Операция range перечисляет все индексы; операция inRange сообщает, находится ли конкретный индекс в диапазоне, заданном парой ограничений.

Реализация имеет право предполагать выполнение следующих правил относительно этих операций:

   range (l,u) !! index (l,u) i == i   -- когда i находится в указанном диапазоне
   inRange (l,u) i == i `elem` range (l,u)
   map index (range (l,u))      == [0..rangeSize (l,u)]

15.1  Выведение экземпляров Ix

Есть возможность вывести (произвести) экземпляр класса Ix автоматически, используя инструкцию deriving в объявлении data (раздел 4.3.3). Объявления таких производных экземпляров класса Ix возможны только для перечислений (т.е. типов данных, имеющих конструкторы без аргументов) и типов данных с одним конструктором, у которого компоненты имеют типы, являющиеся экземплярами класса Ix. Реализация Haskell должна обеспечить экземпляры класса Ix для кортежей по меньшей мере вплоть до 15 размера.


instance  (Ix a, Ix b)  => Ix (a,b) where
        range ((l,l'),(u,u'))
                = [(i,i') | i <- range (l,u), i' <- range (l',u')]
        index ((l,l'),(u,u')) (i,i')
                =  index (l,u) i * rangeSize (l',u') + index (l',u') i'
        inRange ((l,l'),(u,u')) (i,i')
                = inRange (l,u) i && inRange (l',u') i'

-- Экземпляры для остальных кортежей получены по этой схеме:
--
--  instance  (Ix a1, Ix a2, ... , Ix ak) => Ix (a1,a2,...,ak)  where
--      range ((l1,l2,...,lk),(u1,u2,...,uk)) =
--          [(i1,i2,...,ik) | i1 <- range (l1,u1),
--                            i2 <- range (l2,u2),
--                            ...
--                            ik <- range (lk,uk)]
--
--      index ((l1,l2,...,lk),(u1,u2,...,uk)) (i1,i2,...,ik) =
--        index (lk,uk) ik + rangeSize (lk,uk) * (
--         index (lk-1,uk-1) ik-1 + rangeSize (lk-1,uk-1) * (
--          ...
--           index (l1,u1)))
--
--      inRange ((l1,l2,...lk),(u1,u2,...,uk)) (i1,i2,...,ik) =
--          inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
--              ... && inRange (lk,uk) ik

Выведение экземпляров класса Ix

15.2  Библиотека Ix


module Ix ( Ix(range, index, inRange, rangeSize) ) where

class  Ord a => Ix a  where
    range     :: (a,a) -> [a]
    index     :: (a,a) -> a -> Int
    inRange   :: (a,a) -> a -> Bool
    rangeSize :: (a,a) -> Int

    rangeSize b@(l,h) | null (range b) = 0
                      | otherwise      = index b h + 1 
-- NB: замена "null (range b)" на "not (l <= h)"
-- завершится неудачей, если границы являются кортежами. Например,
--  (1,2) <= (2,1)
-- но диапазон (range) тем не менее пуст:
-- range ((1,2),(2,1)) = []

instance  Ix Char  where
    range (m,n) = [m..n]
    index b@(c,c') ci
        | inRange b ci  =  fromEnum ci - fromEnum c
        | otherwise     =  error "Ix.index: Индекс находится за пределами диапазона."
    inRange (c,c') i    =  c <= i && i <= c'

instance  Ix Int  where
    range (m,n) = [m..n]
    index b@(m,n) i
        | inRange b i   =  i - m
        | otherwise     =  error "Ix.index: Индекс находится за пределами диапазона."
    inRange (m,n) i     =  m <= i && i <= n

instance  Ix Integer  where
    range (m,n) = [m..n]
    index b@(m,n) i
        | inRange b i   =  fromInteger (i - m)
        | otherwise     =  error "Ix.index: Индекс находится за пределами диапазона."
    inRange (m,n) i     =  m <= i && i <= n

instance (Ix a,Ix b) => Ix (a, b) -- является производным, для всех кортежей
instance Ix Bool                  -- является производным
instance Ix Ordering              -- является производным
instance Ix ()                    -- является производным


Описание Haskell 98
наверх | назад | вперед | содержание | предметный указатель функций
Декабрь 2002