如何在F#中声明一个通用函数,返回满足多个约束条件的类型?

3

我想写的是:

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”的错误。


更多需要考虑的是:如果我写let x, y = mk Choice1, mk Choice2,那么xy的类型是什么? - Juliet
是的,我当时想到的是"A是T"和"B是T",但仅当这些语句被单独考虑时才正确。Tomas的解决方案放宽了T在两种情况下相同的要求,而kvb的解决方案引入了一个新类型T,满足这两种情况。 - Joh
2个回答

7
约束条件是可以的,但问题在于没有一种类型能够满足约束条件并且同时也是AB的超类型。 match结构需要从两个分支中返回相同的类型,因此您需要添加向上转型(:>)到某种类型,以便该转换适用于这两个分支。该类型可以是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

7
如果您控制类型AB,那么最简单的解决方案就是定义:
type IXY =
  inherit IX
  inherit IY

然后让AB继承IXYmk将返回一个IXY而不是一个通用类型(即使没有约束也没有意义)。


我同意kvb的观点,这是处理这种情况最常见的方法。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接