我是F#的新手.我在乱搞,我发现了一些有趣的东西,我希望有人可以告诉我幕后发生的事情.
所以我做了这个功能:let my_func (x, y) = x + y.
然后我用args调用了函数1并2给了我3.这是我期望发生的事情,但是当我传递两个字符串时,my_func我得到了一个错误,即使它+是一个有字符串的有效运算符.我重新我的代码,但这次只调用my_func与"cat"和" dog"它给了我"cat dog".然后我试图通过1和2回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
@MarcinJuraszek向您展示了如何解决这个问题,但没有说明为什么会这样.
你可以这样想:
F#的类型推断从上到下,从左到右工作 - 所以当系统试图找到my_func它的类型时,会发现从你使用函数的第一行分配类型(第一个例子是ints,第二个是strings) - 如果您根本不使用它或在FSharp Interactive中定义它,它确实默认为int.
声明函数inline使F#能够使用静态解析的类型参数(由于某些细节只能用于inline函数),然后它确实会执行类似于鸭子类型的操作来从声明中找出函数需要静态+算子的类型以某种方式定义.
你可以在函数的类型中看到这个:
val inline my_func :
x: ^a * y: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
Run Code Online (Sandbox Code Playgroud)
这个相当复杂的类型就是这样说的:
必须有一个静态的操作(+) : ^a * ^b -> ^c上^a(认为'a)如果编写的用于+在功能体.正如您所看到的,这比您真正需要的更通用,但这不是问题.F#将实现具体版本(替换泛型类型)以适用于您应用的此函数(因此在您的示例中,my_funcIL 中将有两个实例化;一个用于Ints,一个用于Strings) - 但这不会打扰你在设计时.
所以你现在有一个更通用的功能,可用于:
(+) : Int * Int -> Int 上 Int(+) : String * String -> String 上 String