我在F#中编写了一个简单的函数,并且能够在同一解决方案中的另一个项目中从C#代码中正确调用它.然后我尝试重构,以便我从C#调用的F#函数是部分应用原始函数的结果并收到编译时错误Non-invocable member: 'Calculators.TenPercentCalculator' cannot be used like a method.
这是工作F#:
let TenPercentItemCalculator (paymentItem : PaymentItem) =
1.1M * paymentItem.Amount
let ExtractItems (payment : Payment) = List.ofSeq(payment.PaymentItems)
let TenPercentCalculator (payments : Payment seq) =
payments |> Seq.map ExtractItems |> List.concat |> List.map TenPercentItemCalculator |> List.sum
Run Code Online (Sandbox Code Playgroud)
这里是重构的F#,它不能编译:
let TenPercentItemCalculator (paymentItem : PaymentItem) =
1.1M * paymentItem.Amount
let ExtractItems (payment : Payment) = List.ofSeq(payment.PaymentItems)
let BaseCalculator (itemCalculator: PaymentItem -> decimal) (payments : Payment seq) =
payments |> Seq.map ExtractItems |> List.concat |> List.map itemCalculator |> List.sum
let TenPercentCalculator : (Payment seq -> decimal) = BaseCalculator TenPercentItemCalculator
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,这里是调用TenPercentCalculator
函数的C#代码:
var interest = Calculators.TenPercentAuctionCalculator(SampleLedger.Payments);
Run Code Online (Sandbox Code Playgroud)
原则上,删除参数和使用部分功能应用程序可以提供相同的功能,但存在细微差别.显而易见的是价值限制(但这不适用于此).更精细的是如何编译函数.
即使在F#类型签名中,您也可以看到这一点.考虑:
let normal nums = Array.map ((+) 1) nums
let partial = Array.map ((+) 1)
Run Code Online (Sandbox Code Playgroud)
两者的类型是:
val normal : int [] -> int []
val partial : (int [] -> int [])
Run Code Online (Sandbox Code Playgroud)
如您所见,编译器在部分应用函数时打印其他括号.大多数情况下,您可以忽略它,但这意味着该函数将被编译为返回的属性FSharpFunc<...>
而不是普通的.NET方法.
你仍然可以调用它(如果你还添加引用FSharp.Core
):
Foo.normal(Enumerable.Range(1, 10).ToArray());
Foo.partial.Invoke(Enumerable.Range(1, 10).ToArray());
Run Code Online (Sandbox Code Playgroud)
但是,如果您正在设计易于使用C#的库,那么我将简单地避免在公共API(以及其他F#特定类型)中使用部分函数应用程序.
归档时间: |
|
查看次数: |
168 次 |
最近记录: |