这是一个有点初学者的问题。我一直在尝试验证以下类型的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)
答案 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
这样的内置函数,但我认为它非常具有说服力,并且(希望)很容易理解。
代码:
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