F#比较lambda是否相等

问题描述 投票:0回答:1

我想尝试比较F#lambda的相等性。乍一看,这是不可能的。

let foo = 10
let la = (fun x y -> x + y + foo)
let lb = (fun x y -> x + y + foo)
printfn "lambda equals %b" (la = lb)

产生错误

类型'('a->'b-> int)'不支持'平等'约束,因为它是一个函数类型F#Compiler(1)

但是,令人惊讶的是,可以序列化lambda函数。

open System.Runtime.Serialization.Formatters.Binary
open System.IO
let serialize o =
    let bf = BinaryFormatter()
    use ms = new MemoryStream()
    bf.Serialize(ms,o)
    ms.ToArray()

let ByteToHex bytes = 
    bytes 
    |> Array.map (fun (x : byte) -> System.String.Format("{0:X2}", x))
    |> String.concat System.String.Empty

let foo = 10
let la = (fun x y -> x + y + foo)
let lb = (fun x y -> x + y + foo)

let a = serialize la 
let b = serialize lb

printfn "%s" (ByteToHex a)
printfn "%s" (ByteToHex b)
printfn "lambda equals %b" (a = b)

这表明如果可以序列化它们,可以对其进行比较。但是,对于此示例,检查字节流将显示两个字节之间存在差异。

enter image description here

是否有可能通过智能比较字节数组来解决此问题的策略?

serialization lambda f# equality
1个回答
0
投票

从等效性的角度看,函数没有被有意义地序列化。

Curryable F#中的功能是从FSharpFunc派生的。

let la = (fun x y -> x + y + foo)

将被实现为此类的实例(等效于C#):

[Serializable] class Impl : FSharpFunc<int, int, int>
{
    public int foo;
    Impl(int foo_) => foo = foo_;

    public override int Invoke(int x, int y) =>
        x + y + _foo;
}

二进制序列化捕获的内容将是完整的类型名和foo的值。实际上,如果我们查看字节流中的字符串,则会看到:

test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Program+la@28
foo

la@28是派生类的名称。

lalb的字节流不同之处是实现类的名称。lalb的内容可能完全不同。

例如,您可以将lb更改为let lb = (fun x y -> x * y + foo),并且两次运行的结果都是相同的-重要的是它们在代码中的位置。

© www.soinside.com 2019 - 2024. All rights reserved.