我对F#很新,我想实现以下问题的解决方案: 从随机顺序发现的一系列磁盘路径(例如“C:\ Hello \ foo”“C:”,“C:\ Hello \ bar”等......)如何构建(有效)树。 假设:序列有效,这意味着可以有效地创建树。
所以我尝试使用递归函数(下面的“mergeInto”)实现,该函数将树“就地”与字符串列表(分割路径称为“branch”)合并在一起
这是我的实现,不变性可以防止对输入树的副作用,所以我尝试使用ref单元格作为输入树,但是我遇到了递归的困难。任何解决方案?
open Microsoft.VisualStudio.TestTools.UnitTesting
type Tree =
|Node of string*list<Tree>
|Empty
let rec branchToTree (inputList:list<string>) =
match inputList with
| [] -> Tree.Empty
| head::tail -> Tree.Node (head, [branchToTree tail])
//branch cannot be empty list
let rec mergeInto (tree:Tree ref) (branch:list<string>) =
match !tree,branch with
| Node (value,_), head::tail when String.op_Inequality(value, head) -> raise (ApplicationException("Oops invariant loop broken"))
| Node (value,_), [_] -> ignore() //the branch is singleton and by loop invariant its head is the current Tree node -> nothing to do.
| Node (value,children), _ ->
let nextBranchValue = branch.Tail.Head //valid because of previous match
//broken attempt to retrieve a ref to the proper child
let targetChild = children
|> List.map (fun(child) -> ref child)
|> List.tryFind (fun(child) -> match !child with
|Empty -> false
|Node (value,_) -> value = nextBranchValue)
match targetChild with
|Some x -> mergeInto x branch.Tail //a valid child match then go deeper. NB: branch.Tail cannot be empty here
|None -> tree := Node(value, (Node (nextBranchValue,[])) :: children)//attach the next branch value to the children
| Empty,_ -> tree := branchToTree branch
[<TestClass>]
type TreeTests () =
[<TestMethod>]
member this.BuildTree () =
let initialTree = ref Tree.Empty
let branch1 = ["a";"b";"c"]
let branch2 = ["a";"b";"d"]
do mergeInto initialTree branch1
//-> my tree is ok
do mergeInto initialTree branch2
//->not ok, expected a
// |
// b
// / \
// d c
答案 0 :(得分:2)
您无法ref
对list
中的元素进行ref
,更改list
,然后期望Tree
中的项目发生变化。如果您真的想这样做,那么您应该将引用放入type Tree =
|Node of string*list<Tree ref>
|Empty
let rec branchToTree (inputList:list<string>) =
match inputList with
| [] -> Tree.Empty
| head::tail -> Tree.Node(head, [ref (branchToTree tail)])
类型。
List.map (fun(child) -> ref child)
如果您这样做,请删除{{1}}部分,然后您的代码就可以了。
您可能对zippers感兴趣,它允许您做类似但没有变异的事情。