如何从F#调用一个带有类型为Expression<T>的参数的C#方法?

3

我想在F#中使用Brahma库并调用一个带有表达式参数的方法,但我不知道该如何做。

这是我想翻译的C#代码:

// Create the computation provider
var computationProvider = new ComputationProvider();

// Create a data-parallel array and fill it with data
var data = new DataParallelArray<float>(computationProvider, 
    new[] { 0f, 1f, 2f, 3f, 4f, 5f, 6f });

// Compile the query
CompiledQuery query = computationProvider.Compile<DataParallelArray<float>>
(
    d => from value in d
    select value * 2f
);

// Run the query on this data
IQueryable result = computationProvider.Run(query, data);

// Print out the results
foreach (float value in result)
        Console.WriteLine(result[i]);

// Get rid of all the stuff we created
computationProvider.Dispose();
data.Dispose();
result.Dispose();

Source

2个回答

3
你需要使用F#引用,但是这些会产生F#表达式(Expr)对象,将其转换为CLR表达式有点棘手。
首先,将你的表达式编写成F#引用:
let expr = <@ fun (d : DataParallelArray<float>) -> d.ToString() @>  // real implementation omitted

现在你需要一个将此转换为CLR(LINQ)表达式的工具。我找到了一位名叫Michael的人编写的这个小帮助方法(无法找到全名以便给予完整的功劳,抱歉):

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
open System.Linq.Expressions

let ToLinq (exp : Expr<'a -> 'b>) =
    let linq = exp.ToLinqExpression()
    let call = linq :?> MethodCallExpression
    let lambda = call.Arguments.[0] :?> LambdaExpression
    Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters) 

(请注意,这取决于F# PowerPack,并且PowerPack ToLinqExpression方法被认为是实验性的,因此可能无法接受用于生产代码。)
现在,您只需将ToLinq方法应用于F#表达式并将结果传递给所需的方法即可:
let clrExpression = expr |> ToLinq
// pass clrExpression to Compile method

这对我进行了简化测试;你可能需要提供一些额外的类型提示,并且我没有尝试从你的实际代码中翻译序列表达式。


我猜博主的全名是Michael Giagnocavo。 - Frank

2

需要注意的是,在QuotationEvaluation模块的接口中(至少在Power Pack v1.9.7.8中)ConvExpr不是其中的一部分。(当我尝试使用ConvExpr时,编译器会报错。)该模块接口通过Expr.ToLinqExpression扩展方法进行暴露。 - itowlson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接