I think I have found a satisfying compromise.

I write generic functions using one parameter for each operation, which seems to guarantee that the compiler will perform the optimizations I want it to do.

1
2
3
4
5
6
7
8
9
10
11
12
let inline average2 (scale: float * 'vec -> 'vec) (add: 'vec * 'vec -> 'vec) (add6: 'vec Add6 option) old v1 v2 v3 v4 =
    let (*) k v = scale(k, v)
    let (+) u v = add(u, v)
    
    match add6 with
    // No addMany available, use pair-wise additions (will create many intermediate vectors).
    | None ->
        old + (1.0/6.0) * (v1 + 2.0 * (v2 + v3) + v4)
    // addMany available, use it.
    | Some addM ->
        let tmp = addM(v1, v2, v2, v3, v3, v4)
        old + (1.0/6.0) * tmp

As this is not very friendly towards users of the generic code, I provide an empty class with a single static method returning a record of the specialized generic functions:

1
2
3
4
5
6
7
8
9
type SpecializedFuncs<'Vector> = {
    average : 'Vector -> 'Vector -> 'Vector -> 'Vector -> 'Vector -> 'Vector
    ...
}

type SpecializedFuncsFactory<'Vector> =
    static member inline instantiate(scale, add2, ?add6) =
        {average = average2 scale add2 add6;
         ...}

Using a class and a method allows me to make some parameters optional, which is nicer than forcing the user to pass a None value. Named parameters are another nice feature of methods which come handy here.

1
2
3
4
5
6
7
8
// Instantiate, using add6
let funcs = SpecializedFuncsFactory<Vec3d>.instantiate(scale = scale_Vec3d, add2 = plus_Vec3d, add6 = add6_Vec3d)
let average_Vec3d = funcs.average


// Instantiate, not using add6
let funcs' = SpecializedFuncsFactory<Vec3d>(scale = scale_Vec3d, add2 = plus_Vec3d)
let average_Vec3d' = funcs'.average
By on 10/22/2008 1:02 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper