F#:尝试通过界面复制和更新记录时出错
F#: Error when trying to copy and update record through interface
我正在尝试创建一个函数,将任何平面 seq<IHierarchy>
转换为层次结构。本质上,任何具有 parentID 和 seq 子级的东西都应该能够构成层次结构。我想知道是否可以将 Hierarchy 设为具有 parentID 和 children 属性的基础 class [我们不能,因为记录是密封的 classes] 我想知道是否有可能使它成为一个具有两个抽象字段的 IHierarchy为每个 class(parentID 和 children)实施。
我附上了下面的代码,其中包括一个 makeHierarchy 函数,该函数试图将平面 seq<IHierarchy>
转换为 IHierarcies 的层次结构。但是,当我尝试使用记录复制和更新语法(即:{node with children = ...})时,我收到一条错误消息 "The type IHierarchy does not contain a field children"。我有点困惑如何让 record {with} 语法在界面中为这种类型工作。不可能吗?任何帮助将不胜感激,因为我是 F# 的新手。
module Hierarchy =
type IHierarchy =
abstract member parentID: Option<int>
abstract member children: seq<IHierarchy>
module SalesComponents =
open Hierarchy
type SalesComponentJson = JsonProvider<""" [{ "ID":1, "parentID":0, "name":"All Media" }, { "ID":1, "parentID":null, "name":"All Media" }] """, SampleIsList=true>
type SalesComponent = {
ID: int;
parentID: Option<int>;
children: seq<SalesComponent>;
name: string
}
interface IHierarchy with
member x.parentID = x.parentID
member x.children = x.children |> Seq.map (fun c -> c :> IHierarchy)
open Hierarchy
open SalesComponents
let main argv =
let makeHierarchy hierarchyRecords:seq<IHierarchy> =
let root = hierarchyRecords |> Seq.tryFind (fun sc -> sc.parentID.IsNone)
let rec getHierarchy (node: IHierarchy, scs: seq<IHierarchy>) =
{node with children = scs |> Seq.filter (fun sc -> sc.parentID.IsSome && sc.parentID.Value = node.ID )
|> Seq.map (fun sc -> getHierarchy(sc,scs))}
root |> Option.map (fun r -> getHierarchy(r,hierarchyRecords) )
你需要一个接口吗?您已经拥有由 JSON 类型提供程序定义的源类型。为什么不定义具体的目标类型?
在函数式编程中,最好的设计通常将数据与行为分开。数据就是数据,函数实现行为。您通常不需要多态对象,尽管来自 OOD 背景,但它可能是一个很难改掉的习惯。
如果您需要层次结构,通常可以使用像这样的通用记录类型对其进行建模:
type Graph<'a> = { Node : 'a; Children : Graph<'a> list }
假设您已经使用上述 JSON 类型提供程序定义了 SalesComponentJson
类型,您可以定义一个将此类 JSON 数据转换为层次结构的函数:
// FSharp.Data.JsonProvider<...>.Root list -> Graph<string> list
let createHierarchies (xs : SalesComponentJson.Root list) =
let rec findChildren parentId =
xs
|> List.filter (fun x -> x.ParentId = Some parentId)
|> List.map (fun x -> { Node = x.Name; Children = findChildren x.Id })
xs
|> List.filter (fun x -> x.ParentId.IsNone)
|> List.map (fun root -> { Node = root.Name; Children = findChildren root.Id })
从类型系统的角度来看,无法保证任何给定的 JSON 数据列表不会包含多个没有父 ID 的条目。因此,函数 returns 一个图形列表,或者更确切地说,一个森林。
下面是一些示例数据:
let salesComponents = [
SalesComponentJson.Parse """{ "ID":0, "name":"All Media" }"""
SalesComponentJson.Parse """{ "ID":1, "parentID":0, "name":"Foo" }"""
SalesComponentJson.Parse """{ "ID":2, "parentID":1, "name":"Bar" }"""
SalesComponentJson.Parse """{ "ID":3, "parentID":1, "name":"Baz" }"""
SalesComponentJson.Parse """{ "ID":4, "parentID":0, "name":"Qux" }"""
SalesComponentJson.Parse """{ "ID":5, "parentID":4, "name":"Corge" }""" ]
这是 FSI 的用法示例:
> createHierarchies salesComponents;;
val it : Graph<string> list =
[{Node = "All Media";
Children =
[{Node = "Foo";
Children = [{Node = "Bar";
Children = [];}; {Node = "Baz";
Children = [];}];};
{Node = "Qux";
Children = [{Node = "Corge";
Children = [];}];}];}]
这片森林只有一棵树。
我正在尝试创建一个函数,将任何平面 seq<IHierarchy>
转换为层次结构。本质上,任何具有 parentID 和 seq 子级的东西都应该能够构成层次结构。我想知道是否可以将 Hierarchy 设为具有 parentID 和 children 属性的基础 class [我们不能,因为记录是密封的 classes] 我想知道是否有可能使它成为一个具有两个抽象字段的 IHierarchy为每个 class(parentID 和 children)实施。
我附上了下面的代码,其中包括一个 makeHierarchy 函数,该函数试图将平面 seq<IHierarchy>
转换为 IHierarcies 的层次结构。但是,当我尝试使用记录复制和更新语法(即:{node with children = ...})时,我收到一条错误消息 "The type IHierarchy does not contain a field children"。我有点困惑如何让 record {with} 语法在界面中为这种类型工作。不可能吗?任何帮助将不胜感激,因为我是 F# 的新手。
module Hierarchy =
type IHierarchy =
abstract member parentID: Option<int>
abstract member children: seq<IHierarchy>
module SalesComponents =
open Hierarchy
type SalesComponentJson = JsonProvider<""" [{ "ID":1, "parentID":0, "name":"All Media" }, { "ID":1, "parentID":null, "name":"All Media" }] """, SampleIsList=true>
type SalesComponent = {
ID: int;
parentID: Option<int>;
children: seq<SalesComponent>;
name: string
}
interface IHierarchy with
member x.parentID = x.parentID
member x.children = x.children |> Seq.map (fun c -> c :> IHierarchy)
open Hierarchy
open SalesComponents
let main argv =
let makeHierarchy hierarchyRecords:seq<IHierarchy> =
let root = hierarchyRecords |> Seq.tryFind (fun sc -> sc.parentID.IsNone)
let rec getHierarchy (node: IHierarchy, scs: seq<IHierarchy>) =
{node with children = scs |> Seq.filter (fun sc -> sc.parentID.IsSome && sc.parentID.Value = node.ID )
|> Seq.map (fun sc -> getHierarchy(sc,scs))}
root |> Option.map (fun r -> getHierarchy(r,hierarchyRecords) )
你需要一个接口吗?您已经拥有由 JSON 类型提供程序定义的源类型。为什么不定义具体的目标类型?
在函数式编程中,最好的设计通常将数据与行为分开。数据就是数据,函数实现行为。您通常不需要多态对象,尽管来自 OOD 背景,但它可能是一个很难改掉的习惯。
如果您需要层次结构,通常可以使用像这样的通用记录类型对其进行建模:
type Graph<'a> = { Node : 'a; Children : Graph<'a> list }
假设您已经使用上述 JSON 类型提供程序定义了 SalesComponentJson
类型,您可以定义一个将此类 JSON 数据转换为层次结构的函数:
// FSharp.Data.JsonProvider<...>.Root list -> Graph<string> list
let createHierarchies (xs : SalesComponentJson.Root list) =
let rec findChildren parentId =
xs
|> List.filter (fun x -> x.ParentId = Some parentId)
|> List.map (fun x -> { Node = x.Name; Children = findChildren x.Id })
xs
|> List.filter (fun x -> x.ParentId.IsNone)
|> List.map (fun root -> { Node = root.Name; Children = findChildren root.Id })
从类型系统的角度来看,无法保证任何给定的 JSON 数据列表不会包含多个没有父 ID 的条目。因此,函数 returns 一个图形列表,或者更确切地说,一个森林。
下面是一些示例数据:
let salesComponents = [
SalesComponentJson.Parse """{ "ID":0, "name":"All Media" }"""
SalesComponentJson.Parse """{ "ID":1, "parentID":0, "name":"Foo" }"""
SalesComponentJson.Parse """{ "ID":2, "parentID":1, "name":"Bar" }"""
SalesComponentJson.Parse """{ "ID":3, "parentID":1, "name":"Baz" }"""
SalesComponentJson.Parse """{ "ID":4, "parentID":0, "name":"Qux" }"""
SalesComponentJson.Parse """{ "ID":5, "parentID":4, "name":"Corge" }""" ]
这是 FSI 的用法示例:
> createHierarchies salesComponents;;
val it : Graph<string> list =
[{Node = "All Media";
Children =
[{Node = "Foo";
Children = [{Node = "Bar";
Children = [];}; {Node = "Baz";
Children = [];}];};
{Node = "Qux";
Children = [{Node = "Corge";
Children = [];}];}];}]
这片森林只有一棵树。