F#Tree:节点插入

时间:2014-11-27 15:09:24

标签: insert tree f# treenode

这是一个延伸F# Recursive Tree Validation的问题,我昨天很好地回答了这个问题。

此问题涉及在现有树中插入子项。这是我想要使用的更新类型:

type Name           = string
type BirthYear      = int
type FamilyTree     = Person of Name * BirthYear * Children
and Children        = FamilyTree list

我的最后一个问题是关于检查树的有效性,这是我决定采用的解决方案:

let rec checkAges minBirth = function
    | Person(_,b,_) :: t -> b >= minBirth && checkAges b t
    | [] -> true

let rec validate (Person(_,b,c)) =
    List.forall isWF c && checkAges (b + 16) c

现在我希望能够以下列形式插入一个Person Simon 作为特定Person Hans 的孩子

insertChildOf "Hans" simon:Person casperFamily:FamilyTree;;

因此,输入应为父 name child family tree 。理想情况下,它应该返回一个修改后的族树,即 FamilyTree选项

我正在努力的是合并验证函数以确保它是合法的,并且如果插入Person已经是父级,则可以将其正确地插入到子级列表中 - 可能作为单独的函数。 / p>

欢迎所有帮助,非常感谢 - 谢谢! :)

1 个答案:

答案 0 :(得分:3)

在您发表评论之后,代码将按预期运行:

let insert pntName (Person(_, newPrsnYear, _) as newPrsn) (Person (n,y,ch)) =
    let rec ins n y = function
        | [] -> if y < newPrsnYear && n = pntName then Some [newPrsn] else None
        | (Person (name, year, childs) as person) :: bros ->
            let tryNxtBros() = Option.map (fun x -> person::x) (ins n y bros)
            if y < newPrsnYear && n = pntName then // father OK
                if newPrsnYear < year then // brother OK -> insert here
                    Some (newPrsn::person::bros)
                else tryNxtBros()
            else // keep looking, first into eldest child ...
                match ins name year childs with
                | Some i -> Some (Person (name, year, i) :: bros)
                | _      -> tryNxtBros() // ... then into other childs
    Option.map (fun x -> Person (n, y, x)) (ins n y ch)

在我之前的回答中,我一直避免使用List函数,因为除非树提供遍历,否则我认为它们不适合树结构。

在使用List函数(使用lambdas和combinators)或纯递归的意义上,我可能有点纯粹,但总的来说,我不喜欢混合它们。