Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using F# discriminated union alternative as parameter type

Tags:

types

f#

I am trying to use a specific member of a discriminated union as a parameter type. For example:

type SomeUnion =
   | A of int * int
   | B of string

type SomeType(A(i, j)) =
    member this.I = i
    member this.J = j

let a = A(10, 20)
let instance = SomeType(a)

but this is illegal syntax, and complains with "Unexpected symbol '(' in type definition" for SomeType's param list. This is valid syntax:

let doSomethingWithA (A(i, j)) = i + j

but the type signature is SomeUnion -> int rather than A -> int, and it complains about incomplete pattern match (understandable given the signature).

So is this possible? I believe in F# union members are compiled to CLR classes, so seems theoretically possible, but is it practically (i.e. without using something like reflection)? Otherwise I suppose you have to do the manual OOP way which is more verbose, and can't guarantee complete matches.

like image 414
fhusb Avatar asked Jan 14 '13 13:01

fhusb


1 Answers

I agree that it is surprising that you cannot pattern match the constructor argument. It does work with normal members.

Maybe you can do an explicit match in the constructor, to get a runtime error if the value is wrong:

type SomeType(a) =
    let i, j = match a with | A(k, l) -> k, l
    member this.I = i
    member this.J = j

But otherwise, one must understand that A is not a type. So it is not surprising that the type of doSomethingWithA is not as you expected. And you would have to live with the incomplete pattern match warnings.

like image 184
wmeyer Avatar answered Sep 28 '22 08:09

wmeyer