[Haskell-cafe] [Haskell] Defining Cg, HLSL style vectors in Haskell

Slavomir Kaslev slavomir.kaslev at gmail.com
Tue Nov 28 16:15:46 EST 2006


On 11/28/06, Brian Hulley <brianh at metamilk.com> wrote:
> Slavomir Kaslev wrote:
> > I have to define a couple of float2, float3, float4 Cg, HLSL style
> > vectors in Haskell. At first I was tempted to make them instances of
> > Num, Floating, RealFrac, etc. but some of the functions defined in
> > those classes have no sense for vectors.
>
> I'd suggest that this implies that these classes are not suitable for
> Vectors.
>
> > One such example is signum from class Num.
> >
> > There are several workarounds for this. One may come up with some
> > meaning for vectors of such functions, for example:
> >
> > instance Num Float3 where
> >    .....
> >    signum a | a == Float3 0 0 0 = 0
> >                  | otherwise = 1
>
> This looks a bit unnatural. Also, testing equality of Floats is not
> generally recommended.
>

Agreed about the testing floats remark. The former definition was just
to scratch the point that it's silly to come up with new meanings of
such operations. It's not well typed either. signum is Num a => a->a,
while the former is (Vector b, Num a) => b -> a.

 After giving some thought on signum, I got to the point, that signum
should be defined so that abs x * signum x = x holds. So it can be
defined as signum (Vec2 x y) = Vec 2 (signum x) (signum y).

It turns out that all the functions in Num, Floating, etc. classes can
be given meaningful definitions for vectors in this pattern. That is f
(Vecn x1 x2 .. xn) = Vecn (f x1) ... (f xn). And all expected laws
just work. One can think of that like the way SIMD processor works, it
does the same operations as on floats but on four floats at parallel.

So vectors can be instances of Num, Floating, etc., after all.

> >
> > [snip]
> > I know that I can scrap all those Num, Floating, RealFrac, etc.
> > classes and define class Vector from scratch, but I really don't want
> > to come up and use different names for +, -, etc. that will bloat the
> > code.
>
> While it may be tempting to want to use symbolic operators like + and -,
> these quickly become very confusing when more distinctions need to be made
> (eg between cross product, dot product, and scaling, or between transforming
> a position versus transforming a direction) so I'd argue that for
> readability descriptive names are better than symbols:
>
>     class Num a => Vector v a where
>         plus :: v a -> v a -> v a
>         minus :: v a -> v a -> v a
>         cross :: v a -> v a -> v a
>         dot :: v a -> v a -> a
>         scale :: a -> v a -> v a
>         magSquared :: v a -> a
>

As I already said, I am leaning toward making vectors instances of Num.

>     class Num a => Transform mat vec a where
>         transformPosition :: mat a -> vec a -> vec a
>         transformDirection :: mat a -> vec a -> vec a
>
>     instance Num a => Transform Mat44 Vec4 a where
>         -- ...
>
> If you're doing matrix transformations, you might also like to consider
> using separate PositionN and DirectionN types instead of VecN to make use of
> the type system to catch some math bugs but I haven't looked into this
> myself yet so I don't know whether this would be practical or not.
>

The point of library is to define vectors, not as mathematical
entities, but just like data representation, as they are defined in
Cg/HLSL. One can take other approach and differentiate vectors between
positions and directions as you suggested. In Renderman shading
language, for example, those two different types are called 'point'
and 'normal'.

Cheers

-- 
Slavomir Kaslev


More information about the Haskell-Cafe mailing list