我正在尝试使用区分联合的特定成员作为参数类型。例如:
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)
但这是非法的语法,并且抱怨SomeType的param列表中的“Unexpected symbol”('in type definition'。这是有效的语法:
let doSomethingWithA (A(i, j)) = i + j
但是类型签名是SomeUnion -> int
而不是A -> int
,它抱怨模式匹配不完整(鉴于签名可以理解)。
这可能吗?我相信F#union成员被编译为CLR类,所以理论上似乎可能,但实际上是这样(即没有使用像反射这样的东西)?否则我想你必须做一些更详细的手动OOP方式,并且不能保证完全匹配。
答案 0 :(得分:6)
我同意你不能模式匹配构造函数参数是令人惊讶的。 与普通会员合作。
也许你可以在构造函数中进行显式匹配,如果值错误则会出现运行时错误:
type SomeType(a) =
let i, j = match a with | A(k, l) -> k, l
member this.I = i
member this.J = j
但是否则,必须明白A
不类型。因此,doSomethingWithA
的类型并不像您预期的那样令人惊讶。你必须忍受不完整的模式匹配警告。
答案 1 :(得分:5)
正如wmeyer指出的那样,DU的“A”情况根本不是一种类型,而只是联合类型的一个组成部分。
如果你真的想要自己重用一个联合案例,我看不到任何替代它使它成为一个明确的独立类型。
选项一是使用类型别名:
type TypeA = int * int
type SomeUnion =
| A of TypeA
| B of string
type SomeType(a:TypeA) =
let (i,j) = a
member this.I = i
member this.J = j
let a = (10, 20)
let instance = SomeType(a)
为了清楚起见,我在构造函数中添加了TypeA
注释。
第二种选择是将其包装在单个案例DU中。
type TypeA = TA of int * int
type SomeUnion =
| A of TypeA
| B of string
type SomeType(a:TypeA) =
let (TA(i,j)) = a
member this.I = i
member this.J = j
let a = TA (10, 20)
let instance = SomeType(a)
(请注意,匹配let (TA(i,j)) = a
必须有额外的parens,以免与函数混淆。)
答案 2 :(得分:4)
我的F#有点生疏,但也许你可以做这样的事情(用单声道f#2测试)?
type SomeUnion =
| A of int * int
| B of string
type SomeType(i:int, j:int) =
member this.I = i
member this.J = j
let createSomeType(SomeUnion.A(i,j)) = new SomeType(i,j)
let a = A(10, 20)
let instance = createSomeType(a)