2014-10-31 41 views
5

我是F#的新手。我正在搞乱,我发现了一些有趣的东西,我希望有人能够启发我,看看幕后的情况。为什么函数绑定到它们传递的第一个类型

所以我做了这个功能:let my_func (x, y) = x + y

然后我用参数12给我调用该函数。这是我期望发生的事情,但是当我将两个字符串传递给my_func时,即使+是一个有效的字符串操作符,我也遇到了错误。我重新编写了我的代码,但这次只打电话my_func"cat"" dog"哪给了我"cat dog"。然后我试图通过12返回到my_func只发现my_func不接受整数。

为什么my_func这样表现?

let my_func (x, y) = x + y
my_func (1, 2) // produces => 3
my_func ("cat", " dog") // Error

重新运行程序 ...

let my_func (x, y) = x + y
my_func ("cat", " dog") // produces => "cat dog"
my_func (1, 2) // Error

回答

8

@MarcinJuraszek展示了如何解决这个问题,但只字未提为什么它发生。

你可以认为它像这样:

F#的类型推断工作从上到下左至右 - 所以当系统试图找到my_func它会找到指定类型的类型您正在使用该函数的第一行(第一个示例是int s,第二个是string s) - 如果您完全不使用它或在FSharp Interactive中定义它,它的确将默认为int

声明的功能inline使F#使用statically resolved type parameters(由于一些细节,这是唯一可能与inline功能),然后它确实会做这样的事情鸭打字从声明弄清楚,功能需求以某种方式定义静态运算符的类型。

可以在函数的类型看到这一点:

val inline my_func : 
    x: ^a * y: ^b -> ^c 
    when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 

这个相当复杂类型说只是这样的:

必须有一个静态的运营商(+) : ^a * ^b -> ^c^a(认为'a)用于当你在函数体中写入+。正如你所看到的,这比你真正需要它更通用,但这不是问题。 F#将实现具体的版本(用通用类型替代)以应用此功能(因此在您的示例中,IL中将有两个my_func实例化;一个用于Int s,另一个用于String s) - 但这赢得了“在设计时,你根本不会打扰你。

所以,你现在有一个更通用功能,可用于:

  • (+) : Int * Int -> IntInt
  • (+) : String * String -> StringString
+1

+1伟大的答案。 Se也[这篇由Liam MCLennnan撰写的文章涵盖了类似的地方](http://withouttheloop.com/articles/2014-10-21-fsharp-adhoc-polymorphism/) – 2014-10-31 08:28:49

相关问题