为什么将函数绑定到第一个传递的类型 [英] Why are functions bound to the first type they are passed
问题描述
我是F#的新手.我在四处乱逛,发现一些有趣的东西,希望有人能启发我有关幕后发生的事情.
I'm new to F#. I was messing around and I found something interesting and I was hoping someone could enlighten me as to what is going on behind the scenew.
所以我做了函数:let my_func (x, y) = x + y
.
然后我用args 1
和2
调用了该函数,并给了我3
.这是我预期会发生的情况,但是当我将两个字符串传递给my_func
时,即使+
是带有字符串的有效运算符,我也遇到了错误.我重新运行了代码,但是这次只用"cat"
和" dog"
调用了my_func
,这给了我"cat dog"
.然后,我试图将1
和2
传递回my_func
,只是发现my_func
不再接受整数.
Then I called the function with the args 1
and 2
giving me 3
. This is what I expected to happen but when I passed two strings to my_func
I got an error even though +
is a valid operator with strings. I reran my code but this time only calling my_func
with "cat"
and " dog"
which gave me "cat dog"
. I then tried to pass 1
and 2
back to my_func
only to find that my_func
no long accepts integers.
为什么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 (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
let my_func (x, y) = x + y
my_func ("cat", " dog") // produces => "cat dog"
my_func (1, 2) // Error
推荐答案
@MarcinJuraszek向您展示了如何解决此问题,但对为什么发生却一言不发.
@MarcinJuraszek showed you how to solve this issue but said nothing about why it happens.
您可以这样想:
F#的类型推断从上到下,从左到右-因此,当系统尝试查找my_func
的类型时,它将发现从使用该函数的第一行(第一个示例是int
s,第二个示例是string
s)-如果您根本不使用它或在FSharp Interactive中定义它,则实际上将默认为int
F#'s type inference works top to bottom, left to right - so when the system tries to find the type for my_func
it will find assign the types from the first line where you are using the function (first example it is int
s and the second is string
s) - If you don't use it at all or define it in FSharp Interactive it will indeed default to int
.
将函数声明为inline
可使F#使用静态解析的类型参数(由于某些细节,只有使用inline
函数才有可能),然后它的确会执行类似 duck-typing 的操作,从声明中找出该函数需要静态类型的声明. +
运算符以某种方式定义.
Declaring the function as inline
enables F# to use statically resolved type parameters (due to some details this is only possible with inline
functions) and then it will indeed do something like duck-typing to figure out from the declaration that the function needs types where a static +
operator is defined somehow.
您可以在函数的类型中看到这一点:
You can see this in the type of the function:
val inline my_func :
x: ^a * y: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
这种相当复杂的类型就是这样:
this rather complicated type says just this:
在^a
上必须有一个静态运算符(+) : ^a * ^b -> ^c
(认为是'a
),当您在函数主体中编写+
时要使用该运算符.如您所见,这比您真正需要的更为通用,但这不是问题. F#将针对您应用的此函数的所有出现实现具体版本(用通用类型替换)(因此在您的示例中,IL中将有两个my_func
实例化;一个针对Int
s,一个针对String
s )-但这根本不会在设计时困扰您.
There must be a static operator (+) : ^a * ^b -> ^c
on ^a
(think 'a
) that is used when you write +
in the functions body. As you can see this is even more generic than you really need it but this is no issue. F# will implement concrete versions (with the generic types substituted) for ever occurrence of this function you apply (so in your example there will be two my_func
instantiations in your IL; one for Int
s and one for String
s) - but this won't bother you at design-time at all.
因此,您现在可以使用更多的 generic 函数:
So you now have a more generic function that can be used with:
-
(+) : Int * Int -> Int
-
(+) : String * String -> String
(+) : Int * Int -> Int
onInt
(+) : String * String -> String
onString
这篇关于为什么将函数绑定到第一个传递的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!