F#中的接口,泛型和方法重载以及如何利用其类型推断

时间:2015-11-25 06:43:27

标签: interface f# type-inference overloading f#-4.0

背景:我正在尝试扩展我现有的日志框架,它现在是printfn和朋友之间的静态非线程安全方法的包装器。我的设计目标是:拥有通用接口ILog和具体类,如DbgLogTrace。遗憾的是,我不能使用模块和函数,因为我喜欢在方法上使用ConditionalAttribute

我的工作方法看起来像这样:

type ILog<'T, 'U, 'V> =
    abstract member log: 'T -> unit
    abstract member log: 'U * 'V -> unit

type Dbg<'T, 'U, 'V when 'T :> Printf.StringFormat<string> and 'U :> Printf.StringFormat<'V -> string>>() =
    static member inline _do_other_stuff() = "other stuff"

    static member inline private _helper() = 
        printfn "%s %s" (Dbg<_,_,_>._do_other_stuff())

    interface ILog<'T, 'U, 'V> with
        [<Conditional("DEBUG")>]  // removed from call site
        member this.log(msg) = sprintf msg |> Dbg<_,_,_>._helper()
        [<Conditional("DEBUG")>]  // removed from call site
        member this.log(fmt, a) = sprintf fmt a |> Dbg<_,_,_>._helper()

module TestMe =
    let test() = 
        let dbg = new Dbg<_,_,_>() :> ILog<_,_,_>
        dbg.log("test%i", 2)

这里,编译器和语法检查器和着色器正确检测到dbg.log("test%i", 2)行,这正是我想要的。如果我改为编写"test%s",它也会正确地引发错误。

现在,如果我采用上述方法并对其进行扩展以创建ILog.log方法的更多重载,由于所有类型注释和所需的语法使用Dbg<_,_,_>,这会很快变得非常毛茸茸。 }。其中一些可以隐藏起来,但我仍然认为必须有更好的方法。

我尝试过的一种方法,看起来很FSharpish:

type ILog =
    abstract member log: _ -> unit
    abstract member log: _ * _ -> unit

这会编译界面并分别将类型推断为'a0'a0 -> 'a1(这似乎不对,为什么第二个log成员获得相同的'a0?) 。但是,我找不到任何实现这种过于通用的界面的方法:

type Dbg() =
    interface ILog with
        member this.log v = v + 1 |> ignore      // it won't infer int here

提出:

  

声明的类型参数&#39;?&#39;这里不能使用,因为在编译时无法解析类型参数。

F#4.0是否有一种以更通用的方式声明接口的方式,或者我不得不专门声明它们(虽然这有效,但是很乏味)。

0 个答案:

没有答案