【问题标题】:Why are functions bound to the first type they are passed为什么函数绑定到它们传递的第一种类型
【发布时间】:2014-10-31 05:00:17
【问题描述】:

我是 F# 的新手。我在胡闹,发现了一些有趣的东西,我希望有人能启发我了解幕后发生的事情。

所以我做了函数:let my_func (x, y) = x + y

然后我用参数12 调用函数,给我3。这是我期望发生的,但是当我将两个字符串传递给my_func 时,即使+ 是带有字符串的有效运算符,我也会遇到错误。我重新运行了我的代码,但这次只用"cat"" dog" 调用my_func,这给了我"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

【问题讨论】:

    标签: f#


    【解决方案1】:

    @MarcinJuraszek 向您展示了如何解决此问题,但没有说明为什么会发生这种情况。

    你可以这样想:

    F# 的类型推断从上到下从左到右 - 所以当系统试图找到my_func 的类型时,它会从使用该函数的第一行(第一个示例是 ints,第二个示例是 strings) - 如果您根本不使用它或在 FSharp Interactive 中定义它,它确实默认为 int .

    将函数声明为 inline 使 F# 能够使用 statically resolved type parameters(由于某些细节,这仅适用于 inline 函数)然后它确实会执行类似 duck-typing 的操作从声明中找出函数需要以某种方式定义静态+ 运算符的类型。

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

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

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

    ^a(想想'a)上必须有一个静态运算符(+) : ^a * ^b -> ^c,当您在函数体中编写+ 时会用到它。如您所见,这比您真正需要的更通用,但这不是问题。 F# 将为您应用的此函数的任何出现实现具体版本(替换通用类型)(因此在您的示例中,您的 IL 中将有两个 my_func 实例化;一个用于Ints,一个用于Strings ) - 但这在设计时根本不会打扰您。

    所以你现在有了一个更通用的函数,它可以用于:

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

    【讨论】:

    【解决方案2】:

    您必须使用 inline 关键字声明您的方法才能使其工作:

    let inline my_func (x,y) = x + y
    

    在 MSDN 上阅读更多信息:Inline Functions (F#)

    【讨论】:

      猜你喜欢
      • 2014-12-30
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      • 2021-01-31
      • 2019-10-19
      • 2015-08-01
      • 2012-05-13
      • 2021-09-23
      相关资源
      最近更新 更多