序列化 F# 函数

pil*_*mps 3 f# functional-programming json.net

使用 F# 我有一些我想使用 Newtonsoft.Json 序列化到磁盘的配置。配置数据是一种记录类型。记录类型中的字段之一是 string->bool 类型的函数,用于将字符串与给定值进行比较。例如

(fun (x:string) -> x = "1")
Run Code Online (Sandbox Code Playgroud)

序列化类型成功,但该字段未成功存储(记录为“{}”),因此反序列化失败。这似乎是设计使然。

如何存储函数,以便在反序列化时可以使用它从磁盘填充记录类型并且仍然可以执行?

我已经将引用视为将表达式存储为数据的一种方式,但我不确定这是否可行。如果是,那么我正在努力使其工作。

怎样才能达到我所需要的?

更新;

type Logic = string -> bool
Run Code Online (Sandbox Code Playgroud)

记录类型存储配置;

type Exclusion = 
| FromDataValue of QItem * Logic * ExcludedItems
| FromDataValuesAnd of (QItem * Logic) seq * ExcludedItems          
| FromDataValuesOr of (QItem * Logic) seq seq * ExcludedItems 
Run Code Online (Sandbox Code Playgroud)

排除记录由用户填充,并针对某些数据集运行,从退货集合中排除项目。QItem 表示应用 Logic 函数的数据集中的一个字符串,如果返回 true,则 ExcludedItems 中的项目将从结果中排除。

最初,配置是由解决方案中的用户创建的,因此一切正常。但是,一旦创建了配置,我希望能够将配置保存到光盘,以便在需要时可以加载并再次运行。

所以我需要能够存储它,但我希望能够将它存储为一个字符串,然后在加载时再次运行它。

Aar*_*ach 6

您可以将函数序列化为 JSON,然后反序列化它并稍后使用FSPickler执行该函数:

open MBrace.FsPickler
open MBrace.FsPickler.Json
open System.IO
open System.Text

let serializer = JsonSerializer(indent = true)
let utf8 = UTF8Encoding(false)

let toJson (x: 'a) =
    use stream = new MemoryStream()
    serializer.Serialize(stream, x)
    stream.ToArray() |> utf8.GetString

let parseJson<'a> json =
    use reader = new StringReader(json)
    serializer.Deserialize<'a>(reader)

let f = fun x -> x + 1

let serialized = toJson f

let deserialized = parseJson<int -> int> serialized

deserialized 1 // returns 2
Run Code Online (Sandbox Code Playgroud)

该函数的序列化 JSON 如下所示:

{
  "FsPickler": "4.0.0",
  "type": "Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32]",
  "value": {
    "_flags": "subtype",
    "subtype": {
      "Case": "NamedType",
      "Name": "FSI_0002+serialized@23",
      "Assembly": {
        "Name": "FSI-ASSEMBLY",
        "Version": "0.0.0.0",
        "Culture": "neutral",
        "PublicKeyToken": ""
      }
    },
    "instance": {}
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然instance是空白,但它记录了为函数创建的匿名类型的元数据。这样,只要函数类型在您执行反序列化的 AppDomain 中可用,它就可以在您调用反序列化版本时调用正确的代码。

编辑

如果你想从字面上序列化函数的逻辑,你可以使用 FSPickler 来序列化代码引用:

open MBrace.FsPickler
open MBrace.FsPickler.Json
open FSharp.Quotations
open FSharp.Quotations.Evaluator
open System.IO
open System.Text

let serializer = JsonSerializer(indent = true)
let utf8 = UTF8Encoding(false)

let toJson (x: 'a) =
    use stream = new MemoryStream()
    serializer.Serialize(stream, x)
    stream.ToArray() |> utf8.GetString

let parseJson<'a> json =
    use reader = new StringReader(json)
    serializer.Deserialize<'a>(reader)

let f = <@ fun x -> x + 1 @>

let serialized = toJson f

let deserialized = parseJson<Expr<int -> int>> serialized

let increment = deserialized |> QuotationEvaluator.Evaluate

increment 1
Run Code Online (Sandbox Code Playgroud)

这样,引用将被序列化为 JSON,所有逻辑都描述为表达式树,当您反序列化它时,您可以使用FSharp.Quotations.Evaluator库将其转换为您可以调用的可运行函数。

JSON 现在相当大,但可以在任何地方反序列化和评估:

{
  "FsPickler": "4.0.0",
  "type": "Microsoft.FSharp.Quotations.FSharpExpr`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32]]",
  "value": {
    "attribs": [
      {
        "attribs": [],
        "term": {
          "Case": "CombTerm",
          "Item1": {
            "Case": "NewTupleOp",
            "Item": {
              "Case": "GenericTypeInstance",
              "GenericDefinition": {
                "Case": "NamedType",
                "Name": "System.Tuple`2",
                "Assembly": {
                  "Name": "mscorlib",
                  "Version": "4.0.0.0",
                  "Culture": "neutral",
                  "PublicKeyToken": "b77a5c561934e089"
                }
              },
              "TypeArgs": [
                {
                  "Case": "NamedType",
                  "Name": "System.String",
                  "Assembly": {
                    "_flags": "cached",
                    "id": 9
                  }
                },
                {
                  "Case": "GenericTypeInstance",
                  "GenericDefinition": {
                    "Case": "NamedType",
                    "Name": "System.Tuple`5",
                    "Assembly": {
                      "_flags": "cached",
                      "id": 9
                    }
                  },
                  "TypeArgs": [
                    {
                      "_flags": "cached",
                      "id": 11
                    },
                    {
                      "Case": "NamedType",
                      "Name": "System.Int32",
                      "Assembly": {
                        "_flags": "cached",
                        "id": 9
                      }
                    },
                    {
                      "_flags": "cached",
                      "id": 15
                    },
                    {
                      "_flags": "cached",
                      "id": 15
                    },
                    {
                      "_flags": "cached",
                      "id": 15
                    }
                  ]
                }
              ]
            }
          },
          "Item2": [
            {
              "attribs": {
                "_flags": "cached",
                "id": 4
              },
              "term": {
                "Case": "CombTerm",
                "Item1": {
                  "Case": "ValueOp",
                  "Item1": {
                    "_flags": "subtype",
                    "subtype": {
                      "_flags": "cached",
                      "id": 11
                    },
                    "instance": "DebugRange"
                  },
                  "Item2": {
                    "_flags": "cached",
                    "id": 11
                  },
                  "Item3": null
                },
                "Item2": {
                  "_flags": "cached",
                  "id": 4
                }
              }
            },
            {
              "attribs": {
                "_flags": "cached",
                "id": 4
              },
              "term": {
                "Case": "CombTerm",
                "Item1": {
                  "Case": "NewTupleOp",
                  "Item": {
                    "_flags": "cached",
                    "id": 12
                  }
                },
                "Item2": [
                  {
                    "attribs": {
                      "_flags": "cached",
                      "id": 4
                    },
                    "term": {
                      "Case": "CombTerm",
                      "Item1": {
                        "Case": "ValueOp",
                        "Item1": {
                          "_flags": "subtype",
                          "subtype": {
                            "_flags": "cached",
                            "id": 11
                          },
                          "instance": "C:\\Users\\aeshbach\\AppData\\Local\\Temp\\~vs220A.fsx"
                        },
                        "Item2": {
                          "_flags": "cached",
                          "id": 11
                        },
                        "Item3": null
                      },
                      "Item2": {
                        "_flags": "cached",
                        "id": 4
                      }
                    }
                  },
                  {
                    "attribs": {
                      "_flags": "cached",
                      "id": 4
                    },
                    "term": {
                      "Case": "CombTerm",
                      "Item1": {
                        "Case": "ValueOp",
                        "Item1": {
                          "_flags": "subtype",
                          "subtype": {
                            "_flags": "cached",
                            "id": 15
                          },
                          "instance": 32
                        },
                        "Item2": {
                          "_flags": "cached",
                          "id": 15
                        },
                        "Item3": null
                      },
                      "Item2": {
                        "_flags": "cached",
                        "id": 4
                      }
                    }
                  },
                  {
                    "attribs": {
                      "_flags": "cached",
                      "id": 4
                    },
                    "term": {
                      "Case": "CombTerm",
                      "Item1": {
                        "Case": "ValueOp",
                        "Item1": {
                          "_flags": "subtype",
                          "subtype": {
                            "_flags": "cached",
                            "id": 15
                          },
                          "instance": 11
                        },
                        "Item2": {
                          "_flags": "cached",
                          "id": 15
                        },
                        "Item3": null
                      },
                      "Item2": {
                        "_flags": "cached",
                        "id": 4
                      }
                    }
                  },
                  {
                    "attribs": {
                      "_flags": "cached",
                      "id": 4
                    },
                    "term": {
                      "Case": "CombTerm",
                      "Item1": {
                        "Case": "ValueOp",
                        "Item1": {
                          "_flags": "subtype",
                          "subtype": {
                            "_flags": "cached",
                            "id": 15
                          },
                          "instance": 32
                        },
                        "Item2": {
                          "_flags": "cached",
                          "id": 15
                        },
                        "Item3": null
                      },
                      "Item2": {
                        "_flags": "cached",
                        "id": 4
                      }
                    }
                  },
                  {
                    "attribs": {
                      "_flags": "cached",
                      "id": 4
                    },
                    "term": {
                      "Case": "CombTerm",
                      "Item1": {
                        "Case": "ValueOp",
                        "Item1": {
                          "_flags": "subtype",
                          "subtype": {
                            "_flags": "cached",
                            "id": 15
                          },
                          "instance": 25
                        },
                        "Item2": {
                          "_flags": "cached",
                          "id": 15
                        },
                        "Item3": null
                      },
                      "Item2": {
                        "_flags": "cached",
                        "id": 4
                      }
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    ],
    "term": {
      "Case": "LambdaTerm",
      "Item1": {
        "isMutable104": false,
        "name": "x",
        "stamp": 0,
        "typ": {
          "_flags": "cached",
          "id": 15
        }
      },
      "Item2": {
        "attribs": {
          "_flags": "cached",
          "id": 4
        },
        "term": {
          "Case": "CombTerm",
          "Item1": {
            "Case": "StaticMethodCallOp",
            "Item": {
              "Case": "GenericMethodInstance",
              "GenericDefinition": {
                "Case": "Method",
                "Signature": "T3 op_Addition[T1,T2,T3](T1,T2)",
                "IsStatic": true,
                "DeclaringType": {
                  "Case": "NamedType",
                  "Name": "Microsoft.FSharp.Core.Operators",
                  "Assembly": {
                    "Name": "FSharp.Core",
                    "Version": "4.4.1.0",
                    "Culture": "neutral",
                    "PublicKeyToken": "b03f5f7f11d50a3a"
                  }
                },
                "ReflectedType": null
              },
              "TypeArgs": [
                {
                  "_flags": "cached",
                  "id": 15
                },
                {
                  "_flags": "cached",
                  "id": 15
                },
                {
                  "_flags": "cached",
                  "id": 15
                }
              ]
            }
          },
          "Item2": [
            {
              "attribs": {
                "_flags": "cached",
                "id": 4
              },
              "term": {
                "Case": "VarTerm",
                "Item": {
                  "_flags": "cached",
                  "id": 40
                }
              }
            },
            {
              "attribs": {
                "_flags": "cached",
                "id": 4
              },
              "term": {
                "Case": "CombTerm",
                "Item1": {
                  "Case": "ValueOp",
                  "Item1": {
                    "_flags": "subtype",
                    "subtype": {
                      "_flags": "cached",
                      "id": 15
                    },
                    "instance": 1
                  },
                  "Item2": {
                    "_flags": "cached",
                    "id": 15
                  },
                  "Item3": null
                },
                "Item2": {
                  "_flags": "cached",
                  "id": 4
                }
              }
            }
          ]
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 哇,我没想到这会起作用……这很有趣,但也有点可怕。 (2认同)