F#:不一致的SRTP静态扩展方法类型匹配

时间:2018-06-24 12:17:08

标签: f# constraints extension-methods

我正在尝试使用PrintfFormat来键入解析器的强制解析,它最初似乎适用于int,但是后来对string的相同方法却行不通...而float却可以可以,所以我认为是Value / Ref类型问题,但尝试了bool,但效果不如String。

intfloat起作用,stringbool不起作用!?

(ParseApply方法目前是虚拟实现)

    type System.String  with static member inline ParseApply (path:string) (fn: string -> ^b) : ^b = fn ""
    type System.Int32   with static member inline ParseApply (path:string) (fn: int   -> ^b) : ^b = fn 0
    type System.Double  with static member inline ParseApply (path:string) (fn: float -> ^b) : ^b = fn 0.
    type System.Boolean with static member inline ParseApply (path:string) (fn: bool -> ^b) : ^b = fn true

    let inline parser (fmt:PrintfFormat< ^a -> ^b,_,_,^b>) (fn:^a -> ^b) (v:string) : ^b 
        when ^a : (static member ParseApply: string -> (^a -> ^b) -> ^b) =
        (^a : (static member ParseApply: string -> (^a -> ^b) -> ^b)(v,fn))

    let inline patternTest (fmt:PrintfFormat< ^a -> Action< ^T>,_,_,Action< ^T>>) (fn:^a -> Action< ^T>) v : Action< ^T> = parser fmt fn v

    let parseFn1 = patternTest "adfadf%i" (fun v -> printfn "%i" v; Unchecked.defaultof<Action<unit>> ) // works
    let parseFn2 = patternTest "adf%s245" (fun v -> printfn "%s" v; Unchecked.defaultof<Action<unit>> ) // ERROR
    let parseFn3 = patternTest "adfadf%f" (fun v -> printfn "%f" v; Unchecked.defaultof<Action<unit>> ) // works
    let parseFn4 = patternTest "adfadf%b" (fun v -> printfn "%b" v; Unchecked.defaultof<Action<unit>> ) // ERROR

我在result2函数格式字符串输入中遇到的错误是The type 'string' does not support the operator 'ParseApply',类似地,result4错误是The type 'bool' does not support the operator 'ParseApply'

我不知道为什么会有这种不一致,这是错误还是我错过了什么?

2 个答案:

答案 0 :(得分:4)

我认为这仍然是F#编译器中的一个空白,即扩展成员对于类型约束不可见。有一个WIP PR here可以弥合差距。

答案 1 :(得分:4)

正如@ChesterHusk所说,目前扩展对特质调用不可见。

另请参阅Error on Extension Methods when Inlining

目前,使其工作的方法是使用带有类似操作员特征调用的中间类(操作员通常会查看自己的类和用户定义的类)。

open System

type T = T with
    static member inline ($) (T, _:string) : _ ->_ -> ^b = fun (path:string) (fn: string -> ^b)-> fn ""
    static member inline ($) (T, _:int)    : _ ->_ -> ^b = fun (path:string) (fn: int   -> ^b) -> fn 0
    static member inline ($) (T, _:float)  : _ ->_ -> ^b = fun (path:string) (fn: float -> ^b) -> fn 0.
    static member inline ($) (T, _:bool)   : _ ->_ -> ^b = fun (path:string) (fn: bool -> ^b)  -> fn true

let inline parser (fmt:PrintfFormat< ^a -> ^b,_,_,^b>) (fn:^a -> ^b) (v:string) : ^b = (T $  Unchecked.defaultof< ^a> ) v fn

let inline patternTest (fmt:PrintfFormat< ^a -> Action< ^T>,_,_,Action< ^T>>) (fn:^a -> Action< ^T>) v : Action< ^T> = parser fmt fn v

let parseFn1 = parser "adfadf%i" (fun v -> printfn "%i" v; Unchecked.defaultof<int>)
let parseFn2 = parser "adf%s245" (fun v -> printfn "%s" v; Unchecked.defaultof<string>)
let parseFn3 = parser "adfadf%f" (fun v -> printfn "%f" v; Unchecked.defaultof<float>)
let parseFn4 = parser "adfadf%b" (fun v -> printfn "%b" v; Unchecked.defaultof<bool>)

这可以通过重命名运算符特征调用的方式来使用命名方法来编写。