如何声明一个泛型函数返回满足F#中多个约束的类型?

时间:2010-12-02 14:11:19

标签: f# generics

我想写的是什么:

type A() =
    interface IX with ...
    interface IY with ...

type B() =
    interface IX with ...
    interface IY with ...

let mk t : 'T when 'T :> IX and 'T :> IY =
    match t with
    | Choice1 -> new A()
    | Choice2 -> new B()

注意mk返回类型的类型约束。但它没有编译,编译器抱怨它无法将A和B转换为'T。

2 个答案:

答案 0 :(得分:7)

约束是可以的,但问题是没有类型可以满足约束,并且它将是AB的超类型。

match构造需要从两个分支返回相同的类型,因此您需要将upcast(:>)添加到某种类型,以便转换适用于两个分支。类型可以是IXIY,但这不符合约束条件。

只有当.NET允许您编写类似IX+IY的内容时,这才有可能,这意味着实现两个接口的类型。然后你也可以使用这种类型的值,例如:

let (a:IX+IY) = new A()  // This isn't supported

我认为最好的解决方案是简单地返回一个包含两次相同实例的元组IX * IY,但表示为不同的类型。在这里,你写的这个悔改非常有用:

// Type: 'a -> IX * IY when 'a :> IX and 'a :> IY
let asTuple a = (a :> IX, a :> IY)

let mk t = 
  match t with 
  | Choice1Of2() -> new A() |> asTuple
  | Choice2Of2() -> new B() |> asTuple

答案 1 :(得分:7)

如果您控制类型AB,那么最简单的解决方案就是定义

type IXY =
  inherit IX
  inherit IY

然后让AB继承IXY,而mk只返回IXY而不是通用类型(实际上并非如此)无论如何,即使没有约束,也要有意义。)