Packed vectors : use these whenever possible. The generic vector type is
is represented at runtime by a linked list of boxed values. Packed types,
however, store the vector components sequentially in memory. Vector
operations can be defined using the generic types, and the compiler will
inline and specialize these definitions for the packed types, avoiding any
list cells or unnecessary heap allocations.
Packed vectors are related to their unpacked representations by way of an
associated type. An instance of class PackedVec v declares that v has
a packed representation, and the type of that is Packed v. The packed
constructors are named VecNT where N is 2, 3 or 4 and T is I, F
or D for Int, Float or Double. So the expression Vec3D x y z
constructs a packed 3vector of Doubles, the type of which is Packed (Vec3
Double). The constructor name is also a synonym for the packed type name,
i.e., type Vec3D = Packed (Vec3 Double), so the packed type acts as if it
had been declared data Vec3D = Vec3D x y z.
Storable, Num, Fractional, Fold, Map, and ZipWith instances are
provided for packed vectors, so some operations do not require pack/unpack.
For example, dot does not require pack/unpack because it is defined in
terms of zipWith and fold. However transpose, det,
gaussElim and most others are recursive, and so you'll still need to
use pack/unpack with these. This goes for multmm as well because it
uses transpose. Some functions, like multmv, do not need their
arguments to be unpacked, but the result is a polymorphic vector (:.), so
you will need to pack it again. I admit that this is awkward.
There are also instances for Take, Drop, Last, Head, Tail and
Snoc. These come in handy for thinks like quaternions and homogenous
coordinates.
