Why is F # restricting my code and removing generics?

type VBO<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType> = 
    { Handle : int
      target : BufferTarget
      size : int
      dataSize : int
      data : 'T []
      pos : int
      usage : BufferUsageHint }

type VBO = 
    static member Create(target, size, pos, usage, (data : Vector3 [])) = 
        VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)

    // Type mismatch. Expecting Vector3 but found Vector2
    static member Create(target, size, pos, usage, (data : Vector2 [])) = 
        VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)

    // This construct causes code to be less generic than indicated by the type annotations.
    // The type variable 'T has been constrained to be type 'Vector3'.
    static member CreateImpl(target, size, pos, usage, dataSize, (data : 'T [])) = 
        let h = GL.GenBuffer()
        { Handle = h
          target = target
          size = size
          dataSize = dataSize
          data = data
          pos = pos
          usage = usage }

F # is trying to restrict my code, but I want it to be generic. I don't care what type of data I just need to transfer in the correct data format.

What did I do wrong?

+3
source share
3 answers

The F # compiler seems to specialize in generic types if they are used with a particular instance in the same code block. Try splitting the ad this way:

type VBO<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType> = 
    { Handle : int
      target : BufferTarget
      size : int
      dataSize : int
      data : 'T []
      pos : int
      usage : BufferUsageHint }

type VBO = 
    static member CreateImpl(target, size, pos, usage, dataSize, (data : 'T [])) = 
        let h = GL.GenBuffer()
        { Handle = h
          target = target
          size = size
          dataSize = dataSize
          data = data
          pos = pos
          usage = usage }

type VBO with
    static member Create(target, size, pos, usage, (data : Vector3 [])) = 
        VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)

    static member Create(target, size, pos, usage, (data : Vector2 [])) = 
        VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
+5
source

F # , . , . , , : ( , data, ).

let rec. :

let rec f() = h 5
and g() = h "test"
and h x = x

f , h int , g . h ( h, f g, ).

h generic , :

let rec f() = h 5
and g() = h "test"
and h<'t> (x:'t) :'t = x

, , , , , .

+3

, , , .

, , .

type test = 
    static member test (data:int) = test.actual(data)
    static member test (data:float) =test.actual(data)
    static member actual (data:'t) = ()

, - - .

I think the easiest solution is to change the code to look like

let actual (data:'t) = ()

type test = 
    static member test (data:int) = actual(data)
    static member test (data:float) =actual(data)

Here, the compiler has much more freedom to change the let binding to make it common.

+2
source

All Articles