在哪里可以找到 F# 可区分联合的序列化程序?

发布于 2024-09-18 23:23:28 字数 201 浏览 9 评论 0原文

我需要将使用 F# 判别联合表示的抽象语法树保留为人类可读的紧凑格式,例如 F# 语言中已使用的用于构造判别联合的格式,我可以稍后将其读回判别联合实例。我有点惊讶 F# 库不支持这一点,因为它肯定必须在编译器和 F# 交互中以有效的方式完成。

是否有任何免费/开源实现可以以合理(但不一定非常)有效的方式做到这一点?

注意:我不想要基于 XML 的序列化。

I need to persist an abstract syntax tree represented using F# discriminated unions to a human readable compact format, such as the format already used in the F# language to construct discriminated unions, that I can read back in to discriminated union instances later. I'm a bit surprised the F# library doesn't support this as it surely must be done in an efficient way already in the compiler and F# interactive.

Are there any free/open source implementations out there for doing this in a reasonable (but not necessarily extremely) efficient manner?

Note: I do not want an XML based serialization.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

知足的幸福 2024-09-25 23:23:28

编辑:下面的答案都不符合您的标准,但我发布以防其他寻求联合序列化的人发现它们有用。我不知道任何库方法可以在联合上重新解析 sprintf "%A" 的输出 - 请记住,编译器和 FSI 有一个非常不同的任务,了解范围和处理命名空间、限定名称、阴影等,甚至忽略这些,解析联合所携带的数据(整数、字符串、任意对象等)本身可能是一项完整的任务。

这是联合序列化的一种策略,作为小示例程序的一部分。 (KnownTypeAttribute 可以采用方法名称,并且您可以使用一些反射来获取类型。)这是一种向联合添加少量代码以实现序列化的非常简单的方法。

open Microsoft.FSharp.Reflection 
open System.Reflection 
open System.Runtime.Serialization 
open System.Xml

[<KnownType("KnownTypes")>]
type Union21WithKnownTypes = 
    | Case1 of int * int
    | Case2 of string
    static member KnownTypes() = 
        typeof<Union21WithKnownTypes>.GetNestedTypes(
            BindingFlags.Public 
            ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion 

let dcs = new DataContractSerializer(typeof<Union21WithKnownTypes[]>)
let arr = [| Case1(1,1); Case2("2") |]
printfn "orig data: %A" arr
let sb = new System.Text.StringBuilder()
let xw = XmlWriter.Create(sb)
dcs.WriteObject(xw, arr)
xw.Close()
let s = sb.ToString()
printfn ""
printfn "encoded as: %s" s
printfn ""
let xr = XmlReader.Create(new System.IO.StringReader(s))
let o = dcs.ReadObject(xr)
printfn "final data: %A" o

这是 JSON 版本:

open Microsoft.FSharp.Reflection  
open System.Reflection  
open System.Runtime.Serialization  
open System.Runtime.Serialization.Json  
open System.Xml 

[<KnownType("KnownTypes")>] 
type Union21WithKnownTypes =  
    | Case1 of int * int 
    | Case2 of string 
    static member KnownTypes() =  
        typeof<Union21WithKnownTypes>.GetNestedTypes( 
            BindingFlags.Public  
            ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion  

let dcs = new DataContractJsonSerializer(typeof<Union21WithKnownTypes[]>) 
let arr = [| Case1(1,1); Case2("2") |] 
printfn "orig data: %A" arr 
let stream = new System.IO.MemoryStream()
dcs.WriteObject(stream, arr) 
stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
let bytes = Array.create (int stream.Length) 0uy
stream.Read(bytes, 0, int stream.Length) |> ignore
let s = System.Text.Encoding.ASCII.GetString(bytes)
printfn "" 
printfn "encoded as: %s" s 
printfn "" 
stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
let o = dcs.ReadObject(stream)
printfn "final data: %A" o 

EDIT: Neither of the answers below really meet your criteria, but I'm posting in case others looking for union-serialization find them useful. I don't know offhand of any library way to re-parse the output of sprintf "%A" on a union - keep in mind that the compiler and FSI have a much different task, knowing scopes and dealing with namespaces and qualified names and shadowing and whatnot, and even ignoring that, parsing the data carried by the unions (ints, strings, arbitrary objects, etc.) is potentially a whole task in itself.

Here is one strategy for union serialization, as part of a small sample program. (KnownTypeAttribute can take a method name, and you can use some reflection to get the types.) This is a very easy way to add a tiny bit of code to a union to get serialization.

open Microsoft.FSharp.Reflection 
open System.Reflection 
open System.Runtime.Serialization 
open System.Xml

[<KnownType("KnownTypes")>]
type Union21WithKnownTypes = 
    | Case1 of int * int
    | Case2 of string
    static member KnownTypes() = 
        typeof<Union21WithKnownTypes>.GetNestedTypes(
            BindingFlags.Public 
            ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion 

let dcs = new DataContractSerializer(typeof<Union21WithKnownTypes[]>)
let arr = [| Case1(1,1); Case2("2") |]
printfn "orig data: %A" arr
let sb = new System.Text.StringBuilder()
let xw = XmlWriter.Create(sb)
dcs.WriteObject(xw, arr)
xw.Close()
let s = sb.ToString()
printfn ""
printfn "encoded as: %s" s
printfn ""
let xr = XmlReader.Create(new System.IO.StringReader(s))
let o = dcs.ReadObject(xr)
printfn "final data: %A" o

Here's the JSON version:

open Microsoft.FSharp.Reflection  
open System.Reflection  
open System.Runtime.Serialization  
open System.Runtime.Serialization.Json  
open System.Xml 

[<KnownType("KnownTypes")>] 
type Union21WithKnownTypes =  
    | Case1 of int * int 
    | Case2 of string 
    static member KnownTypes() =  
        typeof<Union21WithKnownTypes>.GetNestedTypes( 
            BindingFlags.Public  
            ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion  

let dcs = new DataContractJsonSerializer(typeof<Union21WithKnownTypes[]>) 
let arr = [| Case1(1,1); Case2("2") |] 
printfn "orig data: %A" arr 
let stream = new System.IO.MemoryStream()
dcs.WriteObject(stream, arr) 
stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
let bytes = Array.create (int stream.Length) 0uy
stream.Read(bytes, 0, int stream.Length) |> ignore
let s = System.Text.Encoding.ASCII.GetString(bytes)
printfn "" 
printfn "encoded as: %s" s 
printfn "" 
stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
let o = dcs.ReadObject(stream)
printfn "final data: %A" o 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文