0

Suppose you want to write a function "gen" that generates a function with a signature given by a list of types:

let gen (sig:Type list) = ....

let sig = [ typeof<int>; typeof<int[]>; typeof<float> ]
let func = gen sig
then func is of type: int -> int[] -> float -> unit

I thought of two possible solutions:

a) Using Reflect Emit, but I don't know if this way we can make the IntelliSense working? Reflect Emit seems to create new .net code, which the IntelliSense might not see, so it might not verify the code at compile time.

b) Using type provider, but I fear is too heavy and may not be practical.

c) Using generics, like the gen<'T1> (sig:Type list) : 'T2 -> unit, this may need recursive calls, but I didn't figured out how to do this.

I would prefer method c), because it is lightweight, and can be checked at compile time. Or is there an alternative approach?

burning_LEGION
  • 13,246
  • 8
  • 40
  • 52
Daniel
  • 1,522
  • 1
  • 12
  • 25

3 Answers3

1

See MakeFunction, http://msdn.microsoft.com/en-us/library/ee353497

Slower than what you can get with Reflection.Emit, but much easier to use and may be adequate for your purposes.

t0yv0
  • 4,714
  • 19
  • 36
1

You've asked how to generate function with some given signature but question misses the point about the body of the function.

Assuming that you have some way to set this body, one possible solution may look like this (warning: slow since it internally uses reflection):

module F = 
    type FST = Microsoft.FSharp.Reflection.FSharpType
    type FSV = Microsoft.FSharp.Reflection.FSharpValue

    let mkFunction (handler : obj list -> obj) : 'T = 
        if not (FST.IsFunction typeof<'T>) then failwith "Function type expected"
        let rec chain args ty = 
            let dty, rty = FST.GetFunctionElements ty
            let impl = 
                if FST.IsFunction rty then 
                    fun o -> chain (o::args) rty
                else
                    fun o -> handler(List.rev (o::args))
            FSV.MakeFunction(ty, impl)
        chain [] typeof<'T> :?> 'T
let f : int -> (int -> int) -> string = 
    F.mkFunction <| 
        fun [:? int as a; :? (int -> int) as f] -> 
            box (string (f a))

If you want to denote desired signature using System.Type list - say good-bye to the intellisence

desco
  • 16,642
  • 1
  • 45
  • 56
0

If you have all the necessary info to generate the code before you run your program you can use Reflection.Emit to generate a DLL with your functions as a preprocessing step and reference that in your main project. This way you get intellisense. If, OTOH, you only know your signature at runtime you can use dynamic methods (http://msdn.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx), but that way you don't get intellisense, obviously.

Regarding options b) and c): I haven't tried the former, but it's still a compile time operation, whereas the latter isn't possible in F#--the language doesn't have variadic functions, printfn & co. are baked in the compiler.

Alex
  • 2,040
  • 2
  • 19
  • 29