F#递归树验证

时间:2014-11-26 16:26:45

标签: recursion tree f#

这是一个有点初学者的问题。我一直在尝试验证以下类型的FamilyTree。我找不到一个简单的方法来做到这一点。所有的帮助将不胜感激。

type BirthYear = int;;
type Tree = Person of BirthYear * Children
and Children = Tree list;;

我想验证一个给定的家谱,以便每个人都比他们的孩子年龄更大,并进一步检查孩子的列表是否按照他们的年龄(最早的)排序。最好使用返回布尔值的函数来完成。有点像这样:

let rec validate (Person(x,child)) = 
    let vali = child |> List.forall (fun (y,_) -> y < x)

3 个答案:

答案 0 :(得分:4)

我会做这样的事情:

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

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

其中minParentAge设置为让孩子在的合理最低年龄。

我希望checkAges在这里更难处理:该函数检查它看到的第一个孩子是否比给定的限制更年轻,然后以当前孩子的年龄递归检查下一个孩子作为新的限制。

请注意一些技巧:

  • 检查儿童年龄的功能以最小生日为输入;这用于验证父母是否足够大,以使第一个孩子合理。

  • List.forall检查列表中所有项目的谓词,并在未满足谓词时提前判断

  • function是一种创建函数的简写,该函数对其参数进行模式匹配。因此,checkAges实际上有两个参数。

答案 1 :(得分:3)

这是使用单个递归函数的非常简单的解决方案。它并不依赖于像List.forall这样的内置函数,但我认为它非常具有说服力,并且(希望)很容易理解。

  • 规则1:每个人都比他们的孩子年长
  • 规则2:儿童名单按年龄顺序排列(最早的)

代码:

let rec isValid = function
    | Person ( _     , []) -> true // Person alone without childs -> always valid
    | Person (minYear, Person (year, childs) :: brothers) ->
        year > minYear &&          // Validate Rules (either 1 or 2)
        isValid (Person (year, childs)) && // Enforce Rule 1
        isValid (Person (year, brothers))  // Enforce Rule 2

我个人觉得List.forall不适合这里,它有助于解决问题的一部分而不是整体,所以你需要将它与更多东西(见其他答案)和最终你无法避免递归函数。

列表函数适用于列表,但对于树,我觉得递归更自然,除非你的树提供了一种遍历它的方法。

答案 2 :(得分:2)

这是一种方法。也许花一些时间来分析它的工作方式对你有所帮助。

let rec check (Person(age, children)) =
    match children with
    | [] -> true
    | Person(eldest, _)::_ -> 
        Seq.pairwise children |> Seq.forall ((<||) (>)) 
            && age > eldest 
            && List.forall check children