如何从C#应用程序将F#函数传递到另一个F#函数?

| 我有包含两个功能的F#类库程序集:
let add a b = a + b
let rec aggregateList list init (op:int -> int -> int) =
    match list with
    |[] -> init
    |head::tail ->
        let rest = aggregateList tail init op
        op rest head
我有一个引用F#库的C#控制台应用程序,并尝试执行以下操作:
FSharpList<int> l = new FSharpList<int>(1, new FSharpList<int>(2, FSharpList<int>.Empty));
int result = myFsLibrary.aggregateList(l, 0, myFsLibrary.add);
但是,编译器抱怨[myFsLibrary.add]无法从\'method group \'转换为
FSharpFunc<int, FSharpFunc<int, int>>
    
已邀请:
您可以使用
FSharpFunc
委托显式创建一个函数。在C#中,创建将所有参数作为元组的函数更方便,因此您可以执行此操作,然后使用
FuncConvert
将函数转换为咖喱类型。就像是:
FuncConvert.FuncFromTupled(new FSharpFunc<Tuple<int, int>, int>(args => 
    arags.Item1 + args.Item2))
但是,如果需要从C#代码中调用某些F#函数,则建议公开一个具有C#友好接口的函数。在这种情况下,我可以使用
Func
委托,并且第一个参数应为
IEnumerable
而不是特定于F#的列表类型:
module List = 
    let AggregateListFriendly inp init (op:Func<int, int, int>) =
        aggregateList (List.ofSeq inp) init (fun a b -> op.Invoke(a, b))
然后,您的C#应用​​程序就可以使用:
List.AggregateListFriendly(Enumerable.Range(0, 10), 0, (a, b) => a + b));
    
其他人已经提供了答案,但我只是介入说您不应该这样做。 不要将F#列表公开给C#。不要将咖喱函数暴露给C#。阻抗不匹配在此边界处可见,因此最好在跨语言组装边界处公开常见的框架类型。看到 http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/fsharp-component-design-guidelines.pdf 以获得更多建议。     
原因是add被导出为普通的.Net样式函数并具有粗糙的签名
int add(int, int)
C#和大多数.Net语言将其视为采用2个12位参数并返回单个12位值的方法。 F#虽然看不到这种功能。而是将
add
视为函数将
int
并返回一个函数,该函数又将takse
int
并返回
int
。这种功能视图使实现类似于curring的操作非常容易。 为了将世界的C#视图转换为F#,您需要做一些魔术才能将方法折叠到自身上。我通过定义一组F#工厂和扩展方法来完成这项任务,以达到我的目的。例如
[<Extension>]
type public FSharpFuncUtil = 

    [<Extension>] 
    static member ToFSharpFunc<\'a,\'b,\'c> (func:System.Func<\'a,\'b,\'c>) = 
        fun x y -> func.Invoke(x,y)

    static member Create<\'a,\'b,\'c> (func:System.Func<\'a,\'b,\'c>) = 
        FSharpFuncUtil.ToFSharpFunc func
我可以使用该库为
add
方法获取合适的F#委托类型,如下所示
var del = FSharpFuncUtil.Create<int, int, int>(myFsLibrary.add);
    

要回复问题请先登录注册