Indexing with fixed-size vectors

In August 2017, Jason Le identified the vector-sized package as the canonical source for efficient fixed-size vectors.

Module Data.Vector.Generic.Sized.Internal of the package exports a new type Vector defined as:

and module Data.Vector.Sized defines the type synonym Vector (where Data.Vector is a module of the vector package):

As shown above, instances of Vector v (n :: Nat) a are derived for a number of classes, but (as of version 1.0.4.0 of the package) there is no instance for the Ix class exported by module Data.Ix of the base package. I wanted to create one.

Data.Vector.Generic.Sized.Internal

The module makes use of a number of extensions to the Haskell 2010 language provided by GHC. Four of them are related to deriving but two are related to types:

The DataKinds extension enables numeric type literals of kind Nat, exported by the GHC.TypeLits module. The KindSignatures extension enables kind signatures to be added to type variables, such as n :: Nat.

instance (Ix a, Ord (v a), VG.Vector v a) => Ix (Vector v n a)

The class Ix exported by module Data.Ix is a re-export from module GHC.Arr. The original class definition includes signatures for range,rangeSize,inRange, and index but also unsafeRangeSize and unsafeIndex. The latter are not re-exported by Data.Ix. Default implementations of index and unsafeIndex refer to each other. Default implementations of rangeSize and unsafeRangeSize refer to unsafeIndex.

Module GHC.Arr defines instances of class Ix for () (the unit type) and tuples of various sizes whose elements are of types that are instances of Ix.

I took a similar approach to instance (Ix a, Ord (v a), Data.Vector.Generic.Vector v a) => Ix (Vector v n a), as shown below:

The class Ix is defined as class Ord a => Ix a where ..., with the constraint Ord a. Vector v n a is an instance of class Ord, but only if v a is an instance of Ord; that must be specified expressly.

instance (Ix a, …) => Ix (Vector v n a)

Can the instance be made more general than the Data.Vector.Generic.Vector v a constraint allows? The answer is ‘yes’.

Class Foldable, exported by module Data.Foldable, promises functions null and foldl'. The former is exported by the Prelude. Data.Vector.and is just a specialised form of a fold.

Class Monoid, exported by the Prelude, promises function mempty.

Class MonadZip, exported by module Control.Monad.Zip, promises functions mzip and mzipWith. There is no mzipWith3, but:

Class IsList, exported by module GHC.Exts, is defined as:

It promises functions toList and fromList and an associated type synonym family Item l (of kind *). The extension TypeFamilies enables the use of associated type synonym families.

To translate:

v [a] must be an instance of IsList (for toList), v a must also be an instance of IsList (for fromList) and types [Item (v a)] and Item (v [a]) must be equivalent (the constraint [Item (v a)] ~ Item (v [a])).