Hob*_*bes 2 c# generics monads extension-methods func
我一直试图通过这篇文章:
http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx
......第1页上的内容让我感到不舒服.特别是,我试图围绕Compose <>()函数,我为自己写了一个例子.考虑以下两个Func:
Func<double, double> addTenth = x => x + 0.10;
Func<double, string> toPercentString = x => (x * 100.0).ToString() + "%";
Run Code Online (Sandbox Code Playgroud)
没问题!很容易理解这两者的作用.
现在,按照本文中的示例,您可以编写一个通用的扩展方法来组合这些函数,如下所示:
public static class ExtensionMethods
{
public static Func<TInput, TLastOutput> Compose<TInput, TFirstOutput, TLastOutput>(
this Func<TFirstOutput, TLastOutput> toPercentString,
Func<TInput, TFirstOutput> addTenth)
{
return input => toPercentString(addTenth(input));
}
}
Run Code Online (Sandbox Code Playgroud)
精细.所以现在你可以说:
string x = toPercentString.Compose<double, double, string>(addTenth)(0.4);
Run Code Online (Sandbox Code Playgroud)
你得到字符串"50%"
到现在为止还挺好.
但这里有一些含糊不清的东西.假设您编写另一种扩展方法,现在您有两个函数:
public static class ExtensionMethods
{
public static Func<TInput, TLastOutput> Compose<TInput, TFirstOutput, TLastOutput>(
this Func<TFirstOutput, TLastOutput> toPercentString,
Func<TInput, TFirstOutput> addTenth)
{
return input => toPercentString(addTenth(input));
}
public static Func<double, string> Compose<TInput, TFirstOutput, TLastOutput>(this
Func<double, string> toPercentString,
Func<double, double> addTenth)
{
return input => toPercentString(addTenth(input + 99999));
}
}
Run Code Online (Sandbox Code Playgroud)
这里有歧义.这两个功能不具有重叠签名吗?是.这甚至可以编译吗?是.哪一个被称为?第二个(显然会给你"错误的"结果)被调用.如果你注释掉任何一个函数,它仍会编译,但你会得到不同的结果.
这似乎是挑剔,但有些东西在这里深深地冒犯了我的感情,我不能把手指放在它上面.它与扩展方法有关吗?它与lambdas有关吗?或者它与Func <>如何允许您参数化返回类型有关?我不确定.
我猜这都是在规范的某个地方解决的,但我甚至不知道Google会发现什么.
救命!
这里没有任何含糊之处.第二个将在完全匹配时被调用.每当匹配不准确时,您将获得第一个函数,因为默认情况下它将与其他所有函数完全匹配.
如果您创建了一个Func<double, string>,而另一个是Func<double, double>在显式指定时调用.Compose <double, double, string>,则编译器有足够的信息来确定第二个版本将是完全匹配,因此它是使用的版本.
但请考虑这个愚蠢的例子:
Func<string, string> doubleString = s => s + s;
Func<DateTime, string> dateToString = date => date.ToString();
Func<DateTime, string> composedFunction = doubleString.Compose(dateToString);
Console.WriteLine(composedFunction(DateTime.Now));
Run Code Online (Sandbox Code Playgroud)
哪个版本被调用?结果是什么?第一个版本,输出是作为连接到自身的字符串的日期.
另一方面,如果你有一个更实际的例子使用Func<double, string>和Func<double, double>并且不像调用Compose那样明确,那么调用哪个版本?
Func<double, string> toPercentString = d => d.ToString("0.0%");
Func<double, double> addTenth = d => d + 0.1;
Console.WriteLine(toPercentString.Compose(addTenth)(0.8));
Run Code Online (Sandbox Code Playgroud)
第一个,因为编译器确定它与第二个完全匹配.由于我不是Eric Lippert或Jon Skeet,我甚至不会试图解释那个绑定.
static void DoSomething(float f, double d) { }
static void DoSomething(double d, float f) { }
Run Code Online (Sandbox Code Playgroud)
...
DoSomething(1, 1);
Run Code Online (Sandbox Code Playgroud)
这是不明确的(因为它不会编译).