[英]F#: Error when trying to copy and update record through interface
我正在嘗試制作一個將任何平面seq<IHierarchy>
轉換為層次結構的函數。 從本質上講,任何具有 parentID 和 seq 子級的東西都應該能夠形成層次結構。 不是將 Hierarchy 設為具有 parentID 和 children 屬性的基類 [我們不能因為記錄是密封類] 我想知道是否有可能將它設為具有我們為每個類(父 ID 和孩子)實現的兩個抽象字段的 IHierarchy .
我附上了下面的代碼,其中包括一個 makeHierarchy 函數,該函數試圖將平面seq<IHierarchy>
轉換為 IHierarchies 的層次結構。 但是,當我嘗試使用記錄復制和更新語法(即:{node with children = ...})時,我收到一條錯誤消息,指出“IHierarchy 類型不包含字段 children”。 我有點困惑如何讓記錄 {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 的條目。 因此,該函數返回一個圖形列表,或者更確切地說,一個森林。
以下是一些示例數據:
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 = [];}];}];}]
這片森林只有一棵樹。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.