开发者

Return an FSharpFunc from F# to C#

开发者 https://www.devze.com 2023-04-12 12:38 出处:网络
I want to write a function in F#, that exposes the following t开发者_C百科ype signature to C#: public static FSharpFunc<FSharpFunc<Unit,Unit>,Unit> foo(Action<Action> f)

I want to write a function in F#, that exposes the following t开发者_C百科ype signature to C#:

public static FSharpFunc<FSharpFunc<Unit,Unit>,Unit> foo(Action<Action> f)

In F# I tried writing:

let foo (f : Action<Action>) : ((unit -> unit) -> unit) = ...

But that produces the C# signature:

public static void foo(Action<Action> f, FSharpFunc<Unit,Unit> x)

The F# has treated my code equivalently to:

let foo (f : Action<Action>) (g : unit -> unit) : unit = ...

Of course, these are equivalent to F#, but very different in C#. Is there anything I can do to produce the C# I want? (F# 2.0.0.0)

As a quick hack, I rewrote my F# to:

let foo (f : Action<Action>) ((unit -> unit) -> unit)[] = ...

Then I just use Head in the C#.


If you write let foo x = fun () -> ... then the F# compiler optimizes the code and compiles it as a method that takes two arguments (instead of a method returning function which is what you need). To get a function value as the result, you need to "do something" before returning the function:

// Will be compiled as method taking Action, FastFunc and returning void
let foo1(x : Action<Action>) : (unit -> unit) -> unit = 
  fun f -> f ()

// Will be compiled as method taking Action and returning FastFunc of FastFunc
let foo2(x : Action<Action>) : ((unit -> unit) -> unit) = 
  ignore ();
  fun f -> f ()

That said, exposing F# function type to C# in any way is a bad pattern and it shouldn't be done. When you have some F# API that is supposed to be used from C#, you should expose functions as delegates, so that C# consumers can use them naturally (without converting Action to F# function explicitly). It is generally easier to write the wrapping on the F# side.


Either:

  1. Add a signature file, with val foo : Action<Action> -> ((unit -> unit) -> unit).
  2. Use a static member of a nominal type, rather than a let-bound value in a module. That is, static member foo (x:Action<Action>) : ((unit -> unit) -> unit) = ...


something like this?

open System 
let foo(x : Action<Action>) : (unit -> unit) -> unit = failwith "..."
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号