将f#函数部分应用程序转换为c#

本文关键字:程序转换 应用 函数部 | 更新日期: 2023-09-27 18:03:17

我正在把这个面向铁路编程的f#源代码翻译成c#。

我在翻译这个SelectMany过载时有困难:


  static member inline SelectMany (this:Result<'TSuccess, 'TMessage>, func: Func<_,_>, mapper: Func<_,_,_>) =
    let mapper = lift2 (fun a b -> mapper.Invoke(a,b))
    let v = bind func.Invoke this
    mapper this v

我已经用上面的映射函数签名:


  public static Result<TResult, TMessage> SelectMany<TSuccess, TMessage, TValue, TResult>(
    this Result<TSuccess, TMessage> result,
    Func<TSuccess, Result<TValue, TMessage>> func,
    Func<TSuccess, TValue, TResult> mapperFunc)

f# lift2函数(我认为我已经正确翻译)接受作为第一个参数的函数签名('a -> 'b -> 'c),但当绑定到mapper让绑定部分应用程序我有问题理解使用的lambda函数。

我通常在部分应用程序中使用这些帮助程序,但我无法将这些f#代码转换为c#。

将f#函数部分应用程序转换为c#

你的Lift2期望一个柯里化的函数,但是传递给SelectMany的映射器没有柯里化。我们来修改一下:

Func<TSuccess, Func<TValue, TResult>> curriedMapper = suc => val => mapperFunc(suc, val);
Func<
    Result<TSuccess, TMessage>, 
    Result<TValue, TMessage>, 
    Result<TResult, TMessage>
> liftedMapper = (a, b) => Lift2(curriedMapper, a, b);
var v = Bind(func, result);
return liftedMapper(result, v);

一般来说,lift2接受具有两个简单类型'a'b参数的函数,并产生一个适用于包装类型M<'a>M<'b>的函数。否则,您可以将其视为接受三个参数:一个简单类型的函数和两个包装好的值,对这些值展开包装,对它们应用函数并包装结果。

假设您的函数正确地从f#移植,SelectMany的主体看起来像这样:

return Lift2(mapper, this, Bind(func, this));

奇怪的Invokes在f#版本中存在,因为Funcs不像c#那样适用,你必须显式调用Invoke。也因为它是未柯化的,mapper.Invoke不能直接传递给lift2 -这就是为什么它被包装在柯化函数中。