2014-04-24 88 views
5

以下輸出「假」F#比較報價

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

printfn "%A" (e1 = e2) 

的原因是無功節點由指針參考,而不是由結構相等比較。 是否已經實現了直觀比較報價的方式?

+0

轉換報價到字符串不是最佳的性能,明智的,不正確或者,作爲全類型信息不會吐出在輸出字符串中... – Liviu

回答

8

有很多原因,比較報價不「工作」默認:

  • 語錄可以包含比較可以不定義其值(參考例如,如果您營造了一些.NET報價不支持比較的對象)。
  • 報價包含有關源代碼中位置的信息 - 因此您的兩個報價不同,只是因爲它們位於不同的行中!
  • 有一個問題,您是否想要將(fun x -> x)(fun y -> 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 
+0

謝謝,我必須實現自己的比較。我希望能夠將不同名稱的變量用相同的類型對待。和對象值。但是,我將不得不收集這些案例作爲比較,並確保正確性。 – Liviu

+0

從理論上講,你想要的東西被稱爲「alpha等價」(http://en.wikipedia.org/wiki/Lambda_calculus#Alpha_equivalence),處理它的一個有用的技巧是忽略變量的名稱,並跟蹤數字(http://en.wikipedia.org/wiki/De_Bruijn_notation)。在實踐中,我認爲你可以添加兩個詞典將變量名稱映射到整數,然後檢查'Var'情況下的數字是否相等。 –

+0

我正在考慮通過引用來實現一個序列。如果我在第一個流中遇到Var1並在第二個流中遇到Var2,那麼隨後如果我在流中遇到Var1,它必須對應於Var2。 – Liviu