F#: Error when trying to copy and update record through interface

我怕爱的太早我们不能终老 提交于 2019-12-01 06:11:06

Do you need an interface for this? You already have the source type defined by the JSON type provider. Why not define a concrete destination type?

In functional programming, the best designs usually separate data from behaviour. Data is data, and functions implement the behaviour. You typically don't need polymorphic objects, although coming from an OOD background, it can be a hard habit to break.

If you need a hierarchy, you can often model it using a generic record type like this:

type Graph<'a> = { Node : 'a; Children : Graph<'a> list }

Assuming that you've already defined the SalesComponentJson type using the JSON type provider as above, you can define a function that transforms such JSON data to hierarchies:

// 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 })

From the perspective of the type system, there's no guarantee that any given list of JSON data doesn't hold more than a single entry with no parent ID. Thus, the function returns a list of graphs, or, rather, a forest.

Here's some example data:

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" }""" ]

and here's a usage example from 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 = [];}];}];}]

This forest only has a single tree.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!