通用函数的类型推断变通方法

时间:2016-09-26 10:31:50

标签: f# type-inference

给出以下参数类型

type SomeDU2<'a,'b> = 
    | One of 'a
    | Two of 'a * 'b

我必须使用函数来检查给定的param是否是相应的union情况而不考虑params

let checkOne x = 
    match x with
    | One _ -> true
    | _ -> false

let checkTwo x = 
    match x with
    | Two _ -> true
    | _ -> false

这非常好用并且符合预期

let oi = checkOne (One 1)
let os = checkOne (One "1")
let tis = checkTwo (Two (1, "1"))
let tsi = checkTwo (Two ("1", 1))

我可以随意切换类型。
现在然而我喜欢将这两个函数组合成一个创建函数

let makeUC () = (checkOne, checkTwo)

然后像这样实例化

let (o,t) = makeUC ()

现在只有它给我这个错误信息

Value restriction. The value 'o' has been inferred to have generic type
    val o : (SomeDU2<'_a,'_b> -> bool)    
Either make the arguments to 'o' explicit or, if you do not intend for it to be generic, add a type annotation.
val o : (SomeDU2<obj,obj> -> bool)

其实我不想要那个 - 我也不需要那个。 可能是它在F#中缺少更高级别的类型的实例 有办法解决这个问题吗?

修改

实际上我的问题根据@johns的评论不完整。 显然我可以做以下事情

let ro1 = o ((One 1) : SomeDU2<int,int>)
let rt1 = t (Two (1,2))

然后向后推断otSomeDU2<int,int> -> bool类型(我觉得这个向后推断非常奇怪)。那么问题是o不再允许下面的内容了。

let ro2 = o ((One "1") : SomeDU2<string,int>)

因此,我必须为o的每个通用参数组合实例化一个特定的SomeDU2实例。

1 个答案:

答案 0 :(得分:3)

即使没有元组,你也会遇到价值限制:

let o = (fun () -> checkOne)()

如果您需要调用函数的结果适用于任何类型的值,那么一种解决方案是使用泛型方法创建名义类型的实例:

type DU2Checker =
    abstract Check : SomeDU2<'a,'b> -> bool

let checkOne = { 
    new DU2Checker with 
    member this.Check(x) = 
        match x with 
        | One _ -> true 
        | _ -> false }

let checkTwo = { 
    new DU2Checker with 
    member this.Check(x) = 
        match x with 
        | Two _ -> true 
        | _ -> false }

let makeUC() = checkOne, checkTwo

let o,t = makeUC()

let false = o.Check(Two(3,4))