【问题标题】:F# compare quotationsF# 比较报价
【发布时间】:2014-04-25 07:37:10
【问题描述】:

以下打印“假”

let e1 = <@@ let d = 1 in d+1 @@>
let e2 = <@@ let d = 1 in d+1 @@>

printfn "%A" (e1 = e2) 

原因是 Var 节点是通过指针引用而不是结构相等来比较的。 是否已经实现了一种直观地比较报价的方法?

【问题讨论】:

  • 将引号转换为字符串在性能方面并不是最优的,也不正确,因为完整的类型信息不会在输出字符串中吐出......

标签: f#


【解决方案1】:

默认情况下比较报价不起作用的原因有很多:

  • 引用可以包含对可能未定义比较的值的引用(例如,如果您创建的引用捕获某些不支持比较的 .NET 对象)。
  • 引用包含有关源代码中位置的信息 - 因此您的两个引用不同只是因为它们位于不同的行上!
  • 存在一个问题,您是否要将 (fun x -&gt; x)(fun y -&gt; y) 视为相同 - 从逻辑上讲,它们是相同的,但从语法上讲,它们不是。

因此,如果您想检查引号是否相等,您只需执行自己的检查即可。对于示例中的基本情况,这样的事情可以解决问题,但它不能处理所有情况:

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns

let rec equal = function
  | Let(v1, ea1, eb1), Let(v2, ea2, eb2) -> 
      v1.Name = v2.Name && equal (ea1, ea2) && equal (eb1, eb2)
  | Var(v1), Var(v2) -> v1.Name = v2.Name
  | Lambda(v1, e1), Lambda(v2, e2) -> v1.Name = v2.Name && equal (e1, e2)
  | Call(None, m1, es1), Call(None, m2, es2) -> 
      m1 = m2 && (List.zip es1 es2 |> List.forall equal)
  | Value(v1), Value(v2) -> v1 = v2
  | _ -> false

【讨论】:

  • 谢谢,我必须自己进行比较。我希望能够将具有不同名称但相同类型的变量视为相等。和对象值。但随着比较的进行,我将不得不收集这些案例并确保正确性。
  • 理论上,你想要的东西叫做“alpha equivalence”(en.wikipedia.org/wiki/Lambda_calculus#Alpha_equivalence),处理它的一个有用技巧是忽略变量的名称,只跟踪一个数字(en.wikipedia.org/wiki/De_Bruijn_notation )。在实践中,我认为您可以添加两个将变量名称映射到整数的字典,然后检查 Var 案例中数字的相等性。
  • 我正在考虑在引用上实现一个序列。如果我在第一个流中遇到 Var1,在第二个流中遇到 Var2,那么如果我在流中遇到 Var1,它必须与 Var2 完全对应。
猜你喜欢
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多