具有类型约束的泛型 class 上的 F# 模式匹配

F# Pattern matching on generic class that has a type constraint

有一个 C# class 喜欢

public abstract class ValueAttrProxy<T> : IAttrProxy where T : IEquatable<T>
{
    public T Value { get; }
    ...
}

在 F# 中,当我尝试像这样进行模式匹配时:

let attrValue (attr:IAttrProxy) =
    match attr with
    | :? ValueAttrProxy<'a> as attr -> attr.Value.ToString()

类型推断似乎有效,但发送到交互式失败并出现以下错误:

错误 FS0071:为类型推断变量应用默认类型 'IEquatable<'a>' 时类型约束不匹配。类型''a'和'IEquatable<'a>'不能统一。考虑添加更多类型约束

我有点困惑是什么问题,或者在哪里需要额外的类型注释。

正在尝试在

这样的匹配模式中指定 IEquatable<'a>
| :? ValueAttrProxy<IEquatable<'a>> as attr -> attr.Value.ToString()

然后甚至类型推断失败,并用相同的错误消息在模式下划线。 如果我将泛型参数限制为特定类型(如 int),那么它就可以工作,但关键是我只想要值的字符串表示形式,而不管它的实际类型是什么。

问题在于,当您编写 :? ValueAttrProxy<'a> 时,编译器需要静态推断 'a 的类型。这不是在运行时根据值确定的类型。如果没有约束,编译器仍然会愉快地编译它,但它会使用 obj 作为 'a.

的默认类型

这个问题与最近 上的一个问题基本相同,您遇到的问题完全相同。那里的答案显示了如何使用反射解决问题,这也适用于您的情况。

如果您控制了 C# 类,那么将 BoxedValue 属性 添加到非通用接口会容易得多:

public interface IAttrProxy {
    public object BoxedValue { get; }
    // (...)
}
public abstract class ValueAttrProxy<T> :
  IAttrProxy where T : IEquatable<T> {
    public T Value { get; }
    // (...)
}

然后您可以只对 IAttrProxy 进行模式匹配并直接访问该值:

let attrValue (attr:IAttrProxy) =
    attr.BoxedValue.ToString()