在同一类型定义中重载一个具有不同参数类型的运算符?

时间:2016-05-05 06:43:55

标签: f#

是否可以在类型定义中使用相同的运算符在运算符的右侧使用不同的类型?

通过名称plugElts定义| ==运算符可以很好地编译,但是稍后在模块RemoverTest中使用它会在右侧提供函数时失败error FS0002: This function takes too many arguments, or is used in a context where a function is not expected

module SampleOperators =

    let inline (|==) (x: ^URel) (wires: ^Wires) =
        (^URel: (static member plugElts: ^URel * ^Wires -> 'R) (x, wires))

module Remover =

    open SampleOperators

    type RemGroup<'G> = RemGroupPass | RemGroupAll | RemGroupExcept of 'G | RemGroupElts of 'G
    type RemMap<'K,'P when 'K: comparison> =
        RemGroup<Map<'K,'P>>
    type RemFun<'K,'P when 'K: comparison> =
        'K * 'P -> bool
    type Rem<'K,'MapVal,'FunVal when 'K:comparison> =
        | Map_ of RemMap<'K,'MapVal>
        | Fun_ of RemFun<'K,'FunVal>

    type X<'K,'P when 'K:comparison> =
        { id: 'K
          vv: Rem<'K,'P,'P> }
        static member inline plugElts (x:X<_,_>, ws:('K * 'P) seq) =
            {x with vv = Map_ (RemGroupElts (Map.ofSeq ws))}

        static member inline plugElts (x:X<_,_>, i:int) =
            {x with vv = Map_ (RemGroupElts (Map.ofSeq [i,i]))}

        static member inline plugElts (x:X<_,_>, fn:('K * 'P -> bool)) =
            {x with vv = Fun_ fn}


module RemoverTest =

    open Remover
    open SampleOperators

    let xxx1 () =
        {id = 1; vv = Map_ RemGroupPass} |== [1,1]   // compiles ok

    let xxx2 () =
        {id = 1; vv = Map_ RemGroupPass} |== 1       // compiles ok

    let xxx3 () =
        ({id = 1; vv = Map_ RemGroupPass}:X<_,_>) |== (fun _ -> bool)  // can't compile

有没有办法让这项工作没有在受歧视的联盟中包装右手边?

谢谢,   卡罗尔

编辑:使用int类型为右侧添加了重载

1 个答案:

答案 0 :(得分:2)

当你在xxx3中调用操作符时,你需要提供一个实际的函数 - 你现在拥有的只是类型声明的等价物。切换到以下内容,它将编译:

let xxx3 () =
    ({id = 1; vv = Map_ RemGroupPass}:X<_,_>) |== (fun _ -> true)

以下是您问题的更紧凑版本:

type MoreFun<'T> = 'T -> int

type X<'T> = 
    { 
        B: int 
        F: MoreFun<'T>
    }
    static member (|==) (a: X<_>, b: int) = { B = b; F = fun (f:int) -> b}
    static member (|==) (a: X<_>, b: MoreFun<_>) = { a with F = b }

module Tests = 
    let one (f: int) = 1
    let t1() = { B = 1; F = one } |== 2
    // let t2() = { B = 1; F = one } |== (fun _ -> int) // Does not work
    let three: MoreFun<_> = (fun _ -> 3)
    let t3() = { B = 1; F = one } |== three
    // You don't need to cast three to be of type MoreFun:
    let t4() = { B = 1; F = one } |== (fun _ -> 3)