Generics F#:尝试通过接口复制和更新记录时出错

Generics F#:尝试通过接口复制和更新记录时出错,generics,interface,f#,record,Generics,Interface,F#,Record,我试图创建一个函数,将任何平面seq转换为层次结构。从本质上讲,任何具有parentID和seq子项的内容都应该能够组成一个层次结构。我不想让层次结构成为一个带有parentID和children属性的基类[我们不能这样做,因为记录是密封的类],而是想知道是否有可能让它成为一个IHierarchy,每个类(parentID和children)都实现两个抽象字段 我附上了下面的代码,其中包括一个makeHierarchy函数,该函数试图将平面seq转换为iHierarchyes的层次结构。然而,当

我试图创建一个函数,将任何平面
seq
转换为层次结构。从本质上讲,任何具有parentID和seq子项的内容都应该能够组成一个层次结构。我不想让层次结构成为一个带有parentID和children属性的基类[我们不能这样做,因为记录是密封的类],而是想知道是否有可能让它成为一个IHierarchy,每个类(parentID和children)都实现两个抽象字段

我附上了下面的代码,其中包括一个makeHierarchy函数,该函数试图将平面
seq
转换为iHierarchyes的层次结构。然而,当我尝试使用记录复制和更新语法(即:{node with children=…})时,我得到一个错误,说“类型IHierarchy不包含字段children”。我有点困惑如何让记录{with}语法在接口中适用于这种类型。不可能吗?任何帮助都将不胜感激,因为我对F#还很陌生

模块层次结构=
类型层次结构=
抽象成员parentID:选项
摘要成员:seq
模块组件=
开放层次结构
键入SalesComponentJson=JsonProvider
类型SalesComponent={
ID:int;
parentID:选项;
子女:seq;
名称:string
}
界面IHierarchy与
成员x.parentID=x.parentID
成员x.children=x.children |>Seq.map(乐趣c->c:>IHierarchy)
开放层次结构
开放式销售组件
让主argv=
让MakeHierarchyHierarchyRecords:seq=
让root=hierarchyRecords |>Seq.tryFind(fun sc->sc.parentID.IsNone)
let rec getHierarchy(节点:IHierarchy,scs:seq)=
{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(funr->getHierarchy(r,hierarchyRecords))

您需要一个接口吗?您已经拥有JSON类型提供程序定义的源类型。为什么不定义一个具体的目的地类型

在函数式编程中,最好的设计通常将数据与行为分开。数据就是数据,函数实现行为。您通常不需要多态对象,尽管它来自OOD背景,但这是一个很难打破的习惯

如果需要层次结构,通常可以使用以下通用记录类型对其进行建模:

type Graph<'a> = { Node : 'a; Children : Graph<'a> list }
从类型系统的角度来看,无法保证任何给定的JSON数据列表不会包含多个没有父ID的条目。因此,函数返回一个图列表,或者更确切地说,返回一个林

以下是一些示例数据:

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 = [];}];}];}]
>创建层次结构salesComponents;;
val it:图形列表=
[{Node=“所有媒体”;
孩子们=
[{Node=“Foo”;
子项=[{Node=“Bar”;
Children=[];};{Node=“Baz”;
子项=[];}];};
{Node=“Qux”;
Children=[{Node=“Corge”;
子项=[];}];}];}]

此林只有一棵树。

IHeirachy不是记录,因此不能使用记录语法。这就是我的想法。有没有关于F#中的设计模式的建议来解决这个问题?我想到的选择似乎都不好:1。不要使用记录类型,请使用具有parentID和children字段的基类,并直接从此基类2继承。将克隆函数作为我的界面的一部分,使子字段可变,在我的函数中克隆记录,然后手动更改子字段。因为这两个都是IHierarchy接口的一部分,所以这应该不是问题,但看起来很难看。我看不到一个优雅的替代方案。非常有用的答案。我想我没有理解的关键是对这样的记录使用泛型。我会尝试一下。
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" }""" ]
> 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 = [];}];}];}]