仅当基础类型执行相等时才实现相等的 F# 容器

标签 f#

编辑:从到目前为止添加的答案和评论看来,我没有正确解释我想要什么。下面是一个例子:

// type not supporting any type of comparison
[<NoEquality>]
[<NoComparison>]
type blah () =
    member x.huha = 0

// make a map, turns out to work whether x supports equality or not
let inline tt x =
    Map.ofList [1, x]       

let test () =
    // maps can be compared for equality if the argument can
    if (tt 1 = tt 2) then failwithf "strange"

    // maps can be made no matter if the argument supports equality
    if (tt (blah ())).Count <> 1 then failwithf "size"

    // this does not compile
    if tt (blah ()) = tt (blah ()) then ....

简而言之,我希望我自己的类型表现得像上面的 map 一样。因此,当类型参数支持时,它应该支持相等,而当类型参数不支持时,它不应该支持。我还希望类型检查器在不支持时阻止我使用相等性,因为它显然可以为内置类型做到这一点。再次感谢。

原始问题:当且仅当某些基础类型支持相等时,各种内置 F# 类型才支持相等。例如,Map<'k, 'd>将支持平等 iff 'd确实(这是在编译时检测到的)。是否可以在用户代码中实现这种行为?这是一次失败的尝试,如果相等是无条件的,则该版本可以正常编译。非常感谢。
[<NoComparison>]
type test_fails<[<EqualityConditionalOn>]'a> (content:'a) =

    let eq_impl (x:test_fails<'a>) (y:obj) =
        let y = y :?> test_fails<'a>
        x.content = y.content

    member x.content = content

    override x.Equals (y:obj) =
        eq_impl x y

[<NoComparison>]
type test_compiles<'a when 'a : equality> (content:'a) =

    let eq_impl (x:test_compiles<'a>) (y:obj) =
        let y = y :?> test_compiles<'a>
        x.content = y.content

    member x.content = content

    override x.Equals (y:obj) =
        eq_impl x y

最佳答案

您已经拥有部分解决方案:使用 [<EqualityConditionalOn>]在泛型参数上。

您缺少的部分:您需要使用 Unchecked.equals 而不是正常的 = map 实现中的运算符(在任何地方检查两个 'a 值的相等性)。 Unchecked.equals在运行时检查该类型是否支持泛型相等。如果是,它会像往常一样比较两个实例/值是否相等;如果不是,则回退到结构相等性检查或 Object.Equals(obj) 的类型实现方法。

关于仅当基础类型执行相等时才实现相等的 F# 容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22302772/

相关文章:

f# - 避免使用 "mutable"变量来调用带有 byref(C# 中的 out)参数的方法?

recursion - F# - 匿名记录的递归

带有重载提取器的 Scala 语言?

f# - 不清楚的函数返回类型问题

c# - 无法从 .NET 4.6 中的 C# Web 项目引用 F# 库?

f# - 如何在 F# 中的函数中使用用户输入的值

f# - 如何在 F# 中注册和实现 .Net 事件的事件处理程序?

f# - FSharp Data的CsvProvider中 "Load"返回的类型是什么

f# - 从 Suave 请求中聚合信息

f# - 与空序列匹配