F#:为什么在重载成员函数时我需要提供参数类型?

时间:2010-08-15 02:47:01

标签: f# operator-overloading type-inference

给出以下代码:

type MyType() =
    static member processString (_string:string) = _string.Substring(0, 1)
    static member processInt (_int:int) = _int.ToString()
    static member processItems = List.map MyType.processString
    static member processItems = List.map MyType.processInt

最后两行不起作用。我必须这样做:

    static member processItems (_strings:string list) = _strings |> List.map MyType.processString
    static member processItems (_ints:int list) = _ints |> List.map MyType.processInt

即使我这样做,第二行也会失败:

    static member processItems (_strings:string list) = _strings |> List.map MyType.processString
    static member processItems = List.map MyType.processInt

由于F#是带有类型推断的所有花哨裤,为什么不能弄清楚两个processItems成员函数有不同的参数签名而不必为两者明确提供参数类型他们??

3 个答案:

答案 0 :(得分:4)

我认为问题出现是因为.NET表示级别的方法和属性之间存在差异。您的原始代码将导致两个具有相同名称的不同静态属性(不受支持)。您的中间示例定义了两个具有相同名称但不同参数类型的方法(支持这些方法)。我不确定为什么最后一个例子不起作用。请注意,我不认为这与推理有任何关系。这有效:

type MyType() = 
    static member processString (_string:string) = _string.Substring(0, 1) 
    static member processInt (_int:int) = _int.ToString() 
    static member processItems l = l |> List.map MyType.processString 
    static member processItems l = l |> List.map MyType.processInt

答案 1 :(得分:2)

对F#有更多了解的人可能会做得更好,但我认为这与成员的参数(即没有参数)的签名(作为值)有关em> 相同。这是由它们不同的返回类型,这不足以区分它们。提供显式参数可以创建不同的输入签名:

type MyType() = 
    static member processString (_string:string) = _string.Substring(0, 1) 
    static member processInt (_int:int) = _int.ToString() 
    static member processFloat (_float:float) = _float.ToString() 
    static member processItems a = a |> List.map MyType.processString  
    static member processItems a = a |> List.map MyType.processInt 
    static member processItems a = a |> List.map MyType.processFloat 

如果您了解C#或C ++,请考虑如何在这些语言中创建类似于原始代码的内容。同样的问题也会得到。

答案 2 :(得分:1)

这里的问题原因不在于类型推断。在第一个示例中,使用定义两个具有相同名称但返回类型不同的属性。

type MyType() =
    static member processString (_string:string) = _string.Substring(0, 1)
    static member processInt (_int:int) = _int.ToString()
    static member processItems = List.map MyType.processString
    static member processItems = List.map MyType.processInt

第二个样本是正确的,因为您明确声明了两个方法

type MyType() =
    static member processString (_string:string) = _string.Substring(0, 1)
    static member processInt (_int:int) = _int.ToString()
    static member processItems (_strings:string list) = _strings |> List.map MyType.processString
    static member processItems (_ints:int list) = _ints |> List.map MyType.processInt

您可以通过删除类型注释来修改它:

type MyType() =
    static member processString (_string:string) = _string.Substring(0, 1)
    static member processInt (_int:int) = _int.ToString()
    static member processItems s = s |> List.map MyType.processString
    static member processItems i = i |> List.map MyType.processInt

在第三个示例中,您尝试使用相同的名称定义属性和方法(C#禁止这样做,通过IIRC,CLI规范不禁止)

type MyType() =
    static member processString (_string:string) = _string.Substring(0, 1)
    static member processInt (_int:int) = _int.ToString()
    static member processItems (_strings:string list) = _strings |> List.map MyType.processString
    static member processItems = List.map MyType.processInt