3
votes

Given the following parametric type

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

I have to functions that check if the given param is the respective union case without regard to params

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

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

This works pretty nice and as expected

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

I can switch the types as I like.
Now However I like to combine those two functions into one creation function

let makeUC () = (checkOne, checkTwo)

and then instantiate like this

let (o,t) = makeUC ()

only it gives me this error message now

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)

Actually I dont want that - nor do I need that. Probably its a instance of missing higher kinded types in F# Is there a way around this?

Edit

Actually me question wasnt complety as per @johns comment below. Obviously I can do the following

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

which then will backwards infer o and t to be of type SomeDU2<int,int> -> bool (I find this backwards inference very strange thou). The problem then is that o wont allow for the below anymore.

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

So I'd have to instantiate a specific o instance for every combination of generic parameters of SomeDU2.

1
Two options: either do what the error message says, or if you use o the message will probably go away - John Palmer
@JohnPalmer added some more info due to your comment - robkuz
How are you planning to use a tuple of functions ? Seems awkward. What are you trying to achieve? - asibahi
@asibahi effectively this github.com/robkuz/fs.UnionCase - robkuz

1 Answers

3
votes

You would run into the value restriction even without the tuple:

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

If you need the results of invoking a function to be applicable to values of any type, then one solution would be to create instances of a nominal type with a generic method:

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))