Data.Ix

Data.Ix

Data.Ix 모듈은 타입의 연속된 부분 범위(contiguous subrange)를 정수로 매핑하는 데 쓰는 Ix 클래스를 정의해요.

출처: Haskell 2010 언어 리포트

본문

19.1 Ix 클래스 (The Ix class)

class Ord a => Ix a where

Ix 클래스는 타입의 연속된 값의 부분 범위를 정수로 매핑하는 데 사용돼요. 주로 배열 인덱싱에 사용돼요(배열 패키지 참고). 각 연산의 첫 번째 인자 (l,u)는 값들의 연속된 부분 범위의 하한과 상한을 지정하는 쌍이에요.

구현은 이 연산들에 대해 다음 법칙들이 성립한다고 가정할 권리가 있어요:

inRange (l,u) i  ==  elem i (range (l,u))
range (l,u) !! index (l,u) i  ==  i            when inRange (l,u) i
map (index (l,u)) (range (l,u)))  ==  [0..rangeSize (l,u)-1]
rangeSize (l,u)  ==  length (range (l,u))

최소 완전 인스턴스(Minimal complete instance): range, index 그리고 inRange.

메서드 (Methods)

range :: (a, a) -> [a]

경계 쌍이 정의하는 부분 범위에 있는 값들의 리스트예요.

index :: (a, a) -> a -> Int

부분 범위 안에 있는 첨자(subscript)의 위치예요.

inRange :: (a, a) -> a -> Bool

주어진 첨자가 경계 쌍이 정의하는 범위 안에 있으면 True를 돌려줘요.

rangeSize :: (a, a) -> Int

경계 쌍이 정의하는 부분 범위의 크기예요.

instance Ix Bool
instance Ix Char
instance Ix Int
instance Ix Int8
instance Ix Int16
instance Ix Int32
instance Ix Int64
instance Ix Integer
instance Ix Ordering
instance Ix Word
instance Ix Word8
instance Ix Word16
instance Ix Word32
instance Ix Word64
instance Ix ()
instance Ix GeneralCategory
instance Ix SeekMode
instance Ix IOMode
instance (Ix a, Ix b) => Ix (a, b)
instance (Ix a1, Ix a2, Ix a3) => Ix (a1, a2, a3)
instance (Ix a1, Ix a2, Ix a3, Ix a4) => Ix (a1, a2, a3, a4)
instance (Ix a1, Ix a2, Ix a3, Ix a4, Ix a5) => Ix (a1, a2, a3, a4, a5)

19.2 Ix 인스턴스 파생 (Deriving Instances of Ix)

데이터 선언에 deriving 절을 사용해 Ix의 인스턴스를 자동으로 파생하는 것이 가능해요. Ix 클래스에 대한 그런 파생 인스턴스 선언은 오직 열거형(enumeration, 즉 nullary 생성자만 갖는 데이터 타입)과 단일 생성자(single-constructor) 데이터 타입에서만 가능한데, 후자의 구성 타입들은 Ix의 인스턴스여야 해요. Haskell 구현은 적어도 크기 15까지의 튜플에 대해 Ix 인스턴스를 제공해야 해요.

열거형(enumerations) 에 대해, nullary 생성자들은 왼쪽에서 오른쪽으로 번호가 매겨지고, 인덱스는 0부터 n-1까지(포함)로 가정돼요. 이는 Enum 클래스가 정의한 번호 매기기와 같아요.

예를 들어, 다음 데이터 타입이 주어졌을 때:

data Colour = Red | Orange | Yellow | Green | Blue | Indigo | Violet

다음이 성립해요:

range (Yellow,Blue)       == [Yellow,Green,Blue]
index (Yellow,Blue) Green == 1
inRange (Yellow,Blue) Red == False

단일 생성자(single-constructor) 데이터 타입에 대해, 파생 인스턴스 선언은 튜플에 대해 보이는 것처럼 이루어져요:

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'

다른 튜플에 대한 인스턴스는 이 방식에서 얻어져요:

-- Instances for other tuples are obtained from this scheme:
--
-- 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

더 알아보기 (Learn more)

  • Ix는 배열 인덱싱의 핵심이므로 Data.Array 모듈과 함께 보면 좋아요.
  • deriving를 통한 Ix 인스턴스 파생은 열거형·단일 생성자 타입에서만 가능하다는 점을 기억해 두면 좋아요.