【问题标题】:F# equals operator complexityF# 等于运算符复杂度
【发布时间】:2012-01-16 18:34:06
【问题描述】:

我对 F# 中的默认“=”(等于)运算符有疑问。它允许比较用户定义的联合类型。问题是:它的复杂性是什么?例如,让我们考虑以下类型:

type Tree<'a> =
  | Nil
  | Leaf of 'a
  | Node of Tree<'a> * Tree<'a>

和以下树:

let a : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Node (Leaf 3, Node (Leaf 4, Leaf 5))), Node (Leaf 6, Nil))
let b : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Node (Leaf 3, Node (Leaf 4, Leaf 5))), Node (Leaf 6, Nil))
let c : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Nil), Node (Node (Leaf 3, Node (Leaf 4, Leaf 5)), Leaf 6))

很明显,这段代码:

printfn "a = b: %b" (a = b)
printfn "a = c: %b" (a = c)
printfn "a = a: %b" (a = a)

产生这个输出:

a = b: true
a = c: false
a = a: true

我希望“a = b”和“a = c”比较需要线性时间。但是“a = a”呢?如果它是恒定的,那么更复杂的结构呢,比如那个:

let d : Tree<int> = Node (a, c)
let e : Tree<int> = Node (a, c)

它会遍历整个 de 结构还是会停在“a = a”和“c = c”?

【问题讨论】:

    标签: f# complexity-theory equals operator-keyword user-defined-types


    【解决方案1】:

    F# 使用结构相等,而 .NET 中的默认 Equals 实现使用引用相等。这意味着,在典型情况下,相等比较是 O(N),其中 N 是正在比较的对象图中的字段数。

    如果您想确保 a = a 得到优化,您可以覆盖 Equals 以首先检查引用相等性,否则返回结构相等性。您需要使用 [&lt;CustomEquality&gt;] 注释您的类型。

    您可以在the F# source code on github 中看到相当冗长的结构平等实现。要遵循调用层次结构,请以 GenericEqualityObj on line 1412 开头。

    【讨论】:

      【解决方案2】:

      编辑:原来的答案是错误的。

      .Net 中Equals() 的通常实现是这样的:

      • 通过引用比较两个实例。如果它们都引用同一个对象,则返回true
      • 比较两个实例的运行时类型。如果它们不同,请返回 false
      • 成对比较类型的每个字段是否相等。如果不相等,返回false,否则返回true

      由于某种原因,F# 跳过了第一步,这意味着时间复杂度始终是线性的。

      由于编译器知道ab是一样的,c的一些子树和a的一些子树是一样的,而且它也知道它们是不可变的,理论上可以使@987654331 @ 和 b 相同的对象并在 c 中重用它们的某些部分。运行时对字符串执行类似的操作,称为string interning。但是(基于反编译的代码)编译器目前似乎没有这样做。

      【讨论】:

      • 我不是反对者,但您描述的“Equals 的通常实现”不适用于 F# 联合。
      • 为什么不呢?它的行为完全一样。
      • 是的,Equals(obj) 可以,但是对于实现 IStructuralEquatable&lt;T&gt;(记录、联合等)的类型,(=) 会调用 Equals(obj, IEqualityComparer)。它的实现由编译器提供,据我所知,它不包括对引用相等性的检查。
      • @Daniel,你是对的。 Equals(obj) 也不检查引用相等性。我不知道我是怎么忽略这一点的。
      • @Brian - 为什么 F# 中的结构相等性不以 ReferenceEquals 开头?
      猜你喜欢
      • 2019-07-06
      • 1970-01-01
      • 1970-01-01
      • 2016-05-13
      • 2010-10-27
      • 1970-01-01
      • 2020-11-10
      • 2012-11-28
      • 2020-02-03
      相关资源
      最近更新 更多