Fsharp /如何将(string * FsTree)列表的类型Node更改为两个路径不能相同的列表

时间:2018-11-29 03:52:58

标签: f# filesystems fscheck fsharpchart

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

给定一种类型: type FsTree = Node of (string * FsTree) list

我想定义一个谓词 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)

1 个答案:

答案 0 :(得分:2)

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

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,所以容易引起混淆,就好像它们可能只是一个函数一样。 / p>

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

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