C#通用方法类型参数推断

Cap*_*sey 8 c# type-inference

有什么方法可以概括这里的类型定义吗?理想情况下,我希望能够更改'testInput'的类型,并在编译时测试正确推断类型.

public static void Run()
{
    var testInput = 3;
    var test = ((Func<int, int>) Identity).Compose<int,int,int>(n => n)(testInput);
    Console.WriteLine(test);
}

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
    return x => f(g(x));
}

public static T Identity<T> (this T value)
{
    return value;
}
Run Code Online (Sandbox Code Playgroud)

更新:我可以指定传递给Compose的函数的类型,但这仍然指定行中的类型.

public static void Run()
{
    var testInput = 3;
    var identity = (Func<int, int>) Identity;
    var test = identity.Compose((int n) => n)(testInput);
    Console.WriteLine(test);
}
Run Code Online (Sandbox Code Playgroud)

一点背景; 我正在通过Wes Dyer的The Monvel of Monads

jef*_*ora 3

好吧,既然我今晚正准备发短信,我自己也会尝试一下。我应该指出,我不是 C# 编译器方面的专家,我还没有阅读过规范(其中任何一个......任何内容),尽管您链接的那篇文章非常有趣,但如果我说我是在撒谎是这方面的专家(甚至 100% 理解)。

抛开警告不谈,我对你的问题的看法是:

有什么方法可以概括这里的类型定义吗?

我认为简短的答案是否定的。根据所提供的信息,C# 编译器的类型推断部分根本没有足够的信息来从各种变量的使用中推断出足够的信息。

正如这里的其他答案所表明的,它可以被简化。您可以使用 @Lee'sIdentityFunc来允许使用 进行类型推断var identity。但是,即使添加了此内容,您的示例代码仍然无法推断Compose.

想象一下以下情况:

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
    return x => f(g(x));
}

public static T Identity<T> (this T value)
{
    return value;
}

public static Func<T, T> IdentityFunc<T>(this T value)
{
    return (Func<T, T>)Identity;
}
Run Code Online (Sandbox Code Playgroud)

public static void Run()
{
    var a = 3; // a is int
    var i = a.IdentityFunc(); // i is Func<int, int>;
    var test = i.Compose(n => n)(a) // test is expected to be int
}
Run Code Online (Sandbox Code Playgroud)

最初,这似乎应该test很容易推断出int。然而, 的返回类型i.Compose只能在事后从其用法中推断出来。C# 编译器显然不允许这样做。

public static void Run()
{
    var a = 3; // a is int
    var i = a.IdentityFunc(); // i is Func<int, int>;
    var c = i.Compose(n => n) // c is Func<T, int> - T cannot be resolved without knowledge of n
    var test = c(a); // ideally have type inference infer c (Func<T, int>) as Func<int, int>
}
Run Code Online (Sandbox Code Playgroud)

c在该示例中,在与编译器一起使用时,a编译器必须回顾性地推断调用 to i.Compose<T, U, V>(n => n)be的返回类型Func<int, int>。这在C#编译器中显然是不可能的。去掉该调用c(a),编译器将不知道 的用法c,这将消除任何推断的可能性T(无论如何都不能)。更高级的类型推断系统可能能够基于通用返回值(可能是 F# - 另一个我不是专家的主题)的使用来进行此类推断。

由于 Wes Dyer 没有提供该特定示例的具体用法,因此未知他是否使用其他一些魔法来允许您尝试实现的类型推断程度。

像埃里克·利珀特这样更有资格的人将能够为您提供更高水平的细节(以及技术准确性/敏锐度)。我读到了他在这里写的关于类型推断问题的精彩回复,但我找不到它。他的博客有很多很棒的信息。如果你有兴趣的话可以尝试联系他。另外,他在这里对这个问题的回答讨论了 monad(最终链接回 Wes Dyer 的文章),您可能有兴趣阅读它:Monad in plain English? (对于没有 FP 背景的 OOP 程序员)

  • 其实我对你的回答没什么可补充的。正如您正确地注意到的,如果没有 lambda 参数的类型,我们就没有足够的信息来从 Compose 的调用站点推断出 T。正如您所指出的,如果我们可以将分析推迟到使用组合结果之前,那么我们可以取得更多进展,但我们没有这样做。 (2认同)