F# Fsharp/如何将(string*FsTree)列表的类型节点更改为2个路径不能相同的列表

F# Fsharp/如何将(string*FsTree)列表的类型节点更改为2个路径不能相同的列表,f#,filesystems,fscheck,fsharpchart,F#,Filesystems,Fscheck,Fsharpchart,在FSharp中,我将执行以下操作 给定类型: 类型FsTree=(字符串*FsTree)列表的节点 我想定义一个谓词 toStringList,以便: toStringList myFsTree给出以下结果 结果: [ ["n1"]; ["n2"; "sub_n2_1"]; ["n2"; "sub_n2_2"]; ["n3"; "sub_n3"; "sub_sub_n3_1"]; ["n3"; "sub_n3"; "sub_sub_n3_2"];

在FSharp中,我将执行以下操作

给定类型:
类型FsTree=(字符串*FsTree)列表的节点

我想定义一个谓词 toStringList,以便:
toStringList myFsTree
给出以下结果

结果:

[
    ["n1"];
    ["n2"; "sub_n2_1"];
    ["n2"; "sub_n2_2"];
    ["n3"; "sub_n3"; "sub_sub_n3_1"];
    ["n3"; "sub_n3"; "sub_sub_n3_2"];
    ["n3"; "sub_n3"; "sub_sub_n3_3"];
    ["n4"];
]
在哪里

let myFsT = Node [
    ("n1", Node []); 
    ("n2", Node [
    ("sub_n2_1", Node []);
    ("sub_n2_2", Node [])
    ]); 
    ("n3", Node [
    ("sub_n3", Node [
    ("sub_sub_n3_1", Node []); 
    ("sub_sub_n3_2", Node []); 
    ("sub_sub_n3_3", Node []); 
    ])
    ]); 
    ("n4", Node [])
]
我知道,到目前为止(下面)我所做的是绝对不正确的。但我真的被困在这里了!有人知道该怎么做吗

let rec test (fst:FsTree) = 
        match fst with
        | Node []              -> []
        | Node ((str, subFst)::restNode) -> 
            [[str] @ (test subFst)] @ (test restNode)

这是一个棘手的问题,因为它需要两个相互递归的函数,一个用于
节点
,另一个用于
节点
内的列表

let rec processNode     prepend node =
    let rec processList prepend listOfNodes =
        match   listOfNodes with
        | []                         -> []
        | (str, subNode) :: restList -> 
            let restList = processList  prepend restList
            let newPrepend = List.append prepend [ str ]
            match processNode newPrepend subNode with
            | []  -> [ newPrepend ]
            | lst -> lst
            @ restList
    match node with Node listOfNodes -> processList prepend listOfNodes

processNode [] myFsT
|> List.iter print
您需要一个递归函数来遍历列表中的元素:
processList

另一个用于检查列表中的子节点:
processNode

之所以会产生混淆,是因为
processNode
所做的一切都是从
Node
获取列表,然后调用
processList
,因此很容易将它们看作是一个函数

OTOH,
processList
是双重递归的。它调用自己遍历列表的元素,并调用
processNode
深入到子树中


还有一个需要传递的累加器参数是
prepend
,它携带路径。

这是一个棘手的参数,因为它需要两个相互递归的函数,一个用于
节点
,另一个用于
节点
内的列表

let rec processNode     prepend node =
    let rec processList prepend listOfNodes =
        match   listOfNodes with
        | []                         -> []
        | (str, subNode) :: restList -> 
            let restList = processList  prepend restList
            let newPrepend = List.append prepend [ str ]
            match processNode newPrepend subNode with
            | []  -> [ newPrepend ]
            | lst -> lst
            @ restList
    match node with Node listOfNodes -> processList prepend listOfNodes

processNode [] myFsT
|> List.iter print
您需要一个递归函数来遍历列表中的元素:
processList

另一个用于检查列表中的子节点:
processNode

之所以会产生混淆,是因为
processNode
所做的一切都是从
Node
获取列表,然后调用
processList
,因此很容易将它们看作是一个函数

OTOH,
processList
是双重递归的。它调用自己遍历列表的元素,并调用
processNode
深入到子树中

还有一个需要传递的累加器参数,它是
prepend
,携带路径