类型扩展不会编译和/或表现出奇怪的编译时行为

时间:2016-11-28 13:22:01

标签: f# extension-methods typeerror overloading

编辑:我同时reported this到F#团队。虽然没有得到答案并不一定意味着这是一个错误,但我在下面重新评估了我自己的问题,至少部分问题没有意义。随意纠正我;)。

以下问题的解决方法是微不足道的,但我对通过展示一些渐进式示例最能解释的行为的原因感兴趣:

所有示例都包含以下内容:

[<AutoOpen>]
module SystemExt =
    open System

    let parseInt = Int64.TryParse

    type Option<'T> with
        /// Creates an Option from a .NET byref result, (true, res) -> Some res, otherwise None
        static member ofByRef (success, result) =
            match success with
            | true -> Some result
            | _ -> None

第一个例子:

type Int64 with
    static member TryParse = parseInt >> Option.ofByRef

let test1 = 
    Int64.TryParse "42"
    |> Option.map ((*) 2L)  // won't compile, type error

第二个例子:

不同的语法,参数的冗余重复,但这会编译,前面的例子没有:

type Int64 with
    static member TryParse s = (parseInt >> Option.ofByRef) s

let test1 = 
    Int64.TryParse "42"
    |> Option.map ((*) 2L)  // compiles fine

第三个例子:

我对这个编译感到有些惊讶,但也许第一个被编译成一个属性,第二个被编译成一个方法,所以也许这就解释了它(虽然通常两个具有不同签名的函数通常是无效的)。

type Int64 with
    static member TryParse = parseInt >> Option.ofByRef
    static member TryParse s = (parseInt >> Option.ofByRef) s

let test1 = 
    Int64.TryParse "42"
    |> Option.map ((*) 2L)

第四个例子:

我无法解释这个,差异只在第一行,使用原始函数Int64.TryParse

type Int64 with
    static member TryParse = Int64.TryParse >> Option.ofByRef
    static member TryParse s = (parseInt >> Option.ofByRef) s  // type error

let test1 = 
    Int64.TryParse "42" 
    |> Option.map ((*) 2L)  // type error

第五个例子,与第一个相同,但以不同方式调用;

let test1 = 
    Int64.get_TryParse() "42"   // compiles fine, why the need to be 
                                // explicit using the property accessor?
    |> Option.map ((*) 2L)

第六个例子:

这是我的出发点,导致上面的其他实验,我仍然没有“得到”这个。

type Int64 with        
    static member TryParse = Int64.TryParse >> Option.ofByRef

let test1 = 
    Int64.TryParse "42"
    |> Option.map ((*) 2L)   // type error

第七个例子:

第六个例子的变体

type Int64 with        
    static member TryParse s = (Int64.TryParse >> Option.ofByRef) s // type error

let test1 = 
    Int64.TryParse "42"  // type error
    |> Option.map ((*) 2L)

最后一个例子(第七个)似乎错误地推断出Int64.TryParse方法的类型,并最终以递归方式调用自身,从而导致类型错误。

我不明白为什么会发生这种情况,解决的顺序是,iirc,类成员在扩展之前进行,在模糊的情况下,成员优先。

第六和第七之间的差异很奇怪。延长线在第六个编译,但不在第七个编译。虽然没有标准方法可以调用第六个例子中重写的TryParse方法。

0 个答案:

没有答案