使用F#discriminated union alternative作为参数类型

fhu*_*usb 5 f# types

我试图使用一个有区别的联合的特定成员作为参数类型.例如:

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)
Run Code Online (Sandbox Code Playgroud)

但这是非法的语法,并抱怨SomeType的param列表中的"Unexpected symbol"('in type definition'.这是有效的语法:

let doSomethingWithA (A(i, j)) = i + j
Run Code Online (Sandbox Code Playgroud)

但类型签名SomeUnion -> int不是A -> int,而是抱怨模式匹配不完整(鉴于签名可以理解).

这可能吗?我相信F#union成员被编译为CLR类,所以理论上似乎可能,但实际上是这样(即不使用像反射这样的东西)?否则我想你必须做手动OOP方式,这更详细,不能保证完全匹配.

wme*_*yer 6

我同意你不能模式匹配构造函数参数是令人惊讶的.它与普通会员的工作.

也许您可以在构造函数中进行显式匹配,以便在值错误时获取运行时错误:

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

但除此之外,我们必须明白,A不是一个类型.因此,这种类型doSomethingWithA并不像您预期​​的那样令人惊讶.你将不得不忍受不完整的模式匹配警告.

  • @fhusb:它实现了IL类型.但是在F#语言级别,DU案例不能作为类型访问. (3认同)

Pao*_*lla 5

我的 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)
Run Code Online (Sandbox Code Playgroud)


Gru*_*oon 5

正如wmeyer指出的那样,DU的"A"情况根本不是一种类型,而只是联合类型的一个组成部分.

如果你真的想要自己重用一个union例子,我看不到任何替代它使它成为一个明确的独立类型.

选项一是使用类型别名:

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

(注意,匹配let (TA(i,j)) = a必须有额外的parens,以免与函数混淆.)