F# 对具有类型约束的泛型类进行模式匹配

标签 f# pattern-matching

有一个像这样的 C# 类

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 .

这个问题和最近在pattern matching against seq<'a> 上的一个问题基本相同你有完全相同的问题。那里的答案展示了如何使用反射解决问题,这也适用于您的情况。

如果您可以控制 C# 类,那么添加 BoxedValue 会容易得多但非通用接口(interface)的属性:

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()

关于F# 对具有类型约束的泛型类进行模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62654464/

相关文章:

haskell - 如何覆盖Haskell中Left上的错误消息?

f# - 将一级函数参数传递给 LINQ 表达式

f# - F# 中的无参数异步工作流是否应该包装在函数中?

java - 在java中使用散列来匹配模式

machine-learning - 识别标志(品牌)的图像识别技术

python - 如何在python中匹配空格和字母数字字符

f# - 哪些区别 "Seq"和 "seq"?

.net - 在 F# 中定义静态类

silverlight - 如何在 F# 中创建一个包含图像和文本的按钮?

android - 密码模式与 Matcher 类不匹配