For instance, you could use

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(* objects *)
type 'a IVector = 
  interface 
    static member dot : 'a -> 'a -> float 
  end

type Float2 = 
  class
    interface (float * float) IVector 
      with
        static member dot (x,y) (x',y') = x*.x' +. y*.y'
      end
  end

let foo = Float2.dot (5.0, 4.0) (6.0, -3.0)

(* or, if you don't need inheritance : the following is more straightforward *)

type 'a vector_ops = {dot : 'a -> 'a -> float ; } 

type Float2 = {dot = fun (x,y) (x',y') -> x*.x' +. y*.y'}

let foo = Float2.dot (5.0, 4.0) (6.0, -3.0)

Hope this helps

By on 9/8/2006 9:20 AM ()

Yes, I know I can do that. The code you posted is equvalent to defining different functions dotf2, dotf3, dotf4 (though the exact code you posted doesn't compile).
I was asking for a definition of a generic function dot with the already metntioned compile time restriction.
Can't this be achived with using some OCaml type system vodoo?

By on 9/8/2006 11:26 AM ()

Let me refrase the question a little.

I want to have several types float2, float3, float4 that are just tupples of floats. I want to have function dot that can accept two floatn s, and fail to compile when given parameter of type floatk and floatl when k != l.

How should the definition of dot look like?

By on 9/8/2006 11:37 AM ()

Hi Slovomir,

The core type system of ML-like languages does not directly support this kind of "polytypic" definition. However, you can simulate it in F# through the use of overloaded operators. Here is a code sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 

// Define the operator that maps uses of the binary operator
// .*. through to calls to a corresponding static member on
// the type of the first argument.  Operators of this sort must always
// be inlined.  
let inline (.*.) x y = 
   (^a: (static member (.*.) : ^a * ^a -> ^b) (x,y))


// Define the Vector2 type with the corresponding member
// implemented.  For fun we've also implemented some standard 
// operators whose mappings are defined in 
// Microsoft.FSharp.MLLib.Pervasives (see pervasives.fs):
//     +  (vector addition) 
//     -  (vector subtraction) 
//     .* (pointwise-multiplication) 
type Vector2 = 
  { x: float; 
    y: float }
  with 
    static member (+)(v1,v2) = { x = v1.x + v2.x; y = v1.y + v2.y }
    static member (-)(v1,v2) = { x = v1.x - v2.x; y = v1.y - v2.y }
    static member (.*)(v1,v2) = { x = v1.x * v2.x; y = v1.y * v2.y }
    static member (.*.)(v1,v2) = v1.x * v2.x + v1.y * v2.y
  end

let vec2 x y = { new Vector2 with x=x and y=y }
let example1 = (vec2 3.0 4.0) .*. (vec2 4.0 5.0)

// You can now do the same thing for Vector3 etc.
type Vector3 = 
  { x: float; 
    y: float; 
    z: float }
  with 
    static member (+)(v1,v2)  = { x = v1.x + v2.x; y = v1.y + v2.y; z = v1.z + v2.z }
    static member (-)(v1,v2)  = { x = v1.x - v2.x; y = v1.y - v2.y; z = v1.z - v2.z  }
    static member (.*)(v1,v2) = { x = v1.x * v2.x; y = v1.y * v2.y; z = v1.z * v2.z  }
    static member (.*.)(v1,v2) = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
  end

let vec3 x y z = { new Vector3 with x=x and y=y and z=z }
let example2 = (vec3 3.0 4.0 5.0) .*. (vec3 4.0 5.0 6.0)

// If you want you can also give alpha-numeric names to operators,
// e.g.
let inline dot x y = 
   (^a: (static member DotProduct : ^a * ^a -> ^b) (x,y))

There are limits to the applicability of this technique (defining zillions of new operators is not recommended - where possible stick to those defined in the F# library pervasives.fs, or perhaps add a few that correspond to intuitive definitions). But the technique does give a powerful form of adhoc overloading, especially if used with types written in F#.

By on 9/8/2006 10:23 PM ()

Thank you very much. That was helpful.

What are the limitations of OCaml type system? Where can I read more about it?

By on 9/9/2006 12:56 AM ()

While mostly similar, the F# and OCaml type systems are not fully compatible. Some limitations/capabilities that apply to F# don't apply to OCaml, and vice versa.

By on 9/9/2006 2:49 AM ()
1
2
3
4
type Vector =
    | Float2 of float * float
    | Float3 of float * float * float
    | Float4 of float * float * float * float

means that they are all of the same type, and thus the compiler cannot know whether the arguments are invalid. Basically, for the compiler,

1
val dot : Vector -> Vector

is like having

1
val dot : int -> int

, where it is clear the compiler cannot know that it should not compile foo 5 9. Likewise he cannot it should not compile Float2 and Float3.

You can therefore stick with exception handling, or use differing types.

If you have several functions like this, you might want to either use objects or modules...

By on 9/8/2006 12:26 AM ()

Thank you for the reply. But you didn't answer my question.

You can therefore stick with exception handling, or use differing types.

What types shoud I use?

By on 9/8/2006 8:16 AM ()
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