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

如何在F#中声明返回满足多个约束的类型的泛型函数?,f#,generics,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 -> n

我想写的是:

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'。

约束是可以的,但问题是没有满足约束的类型,它将是
A
B
的超类型

match
构造需要从两个分支返回相同的类型,因此您需要向某个类型添加向上转换(
:>
),以便转换对两个分支都有效。类型可以是
IX
IY
,但这不能满足约束

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

let (a:IX+IY) = new A()  // This isn't supported
我认为最好的解决方案是简单地返回一个tuple
IX*IY
,其中包含两次相同的实例,但表示为不同的类型。在这里,您编写的constriant非常有用:

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

如果控制类型
A
B
,则最简单的解决方案是定义

type IXY =
  inherit IX
  inherit IY

然后让
A
B
继承
IXY
mk
只返回一个
IXY
,而不是泛型类型(即使没有约束也没有意义)。

只是为了好玩,比较C#中的等效代码。你试图返回一个具体的'T'类型,但你在函数的其余部分不使用该类型——你试图返回一个具体的a或B,类型检查器无法确定你真正想要的是什么。需要考虑的更多:如果我写
let x,y=mk Choice1,mk Choice2
,那么
x
y
有哪些类型?对,我认为“A是-A T”和“B是-A T”,但这只有在独立考虑这些陈述时才是正确的。Tomas的解决方案放宽了T在两种情况下都相同的要求,kvb的解决方案引入了一种新的类型T来满足这两种情况。我同意kvb的观点,这是解决这类问题最常见的方法