【问题标题】:F# Recursive Tree ValidationF# 递归树验证
【发布时间】:2014-11-27 05:50:33
【问题描述】:

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

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)

【问题讨论】:

  • 我尝试过使用 List.forall 和 List.collect,但仅用于一个简单的功能。我无法弄清楚递归部分,因此我可以遍历整个树。
  • 请与您分享一个sn-p - 如果您有什么要开始的,我相信每个人都会更乐意提供帮助。至少在树上进行模式匹配,或者类似的东西!
  • 以上是我走过的最远的地方

标签: recursion tree f#


【解决方案1】:

我会这样做:

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 实际上有两个参数。

【讨论】:

    【解决方案2】:

    这是一个使用单个递归函数的非常简单的解决方案。它不依赖于像 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 不太适合这里,它有助于解决问题的一部分而不是整体,所以你需要将它与更多的东西结合起来(见其他答案),最后你无法避免递归函数。

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

    【讨论】:

    • 这实际上是复制树。
    • 是的,但是它重新创建节点以匹配递归函数的参数,您可以轻松地将其包装在一个单行非递归函数中,以便丢弃 DU 并直接工作与列表。
    【解决方案3】:

    这是一种方法。也许花一些时间分析它的工作原理会对您有所帮助。

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

    【讨论】:

    • 使用 ((&lt;||)(&gt;)) 之类的东西并没有让你的理解变得那么容易;-)
    • 输入实际上不是年龄,而是生日。 (年,正如现在问题中所阐明的那样。)因此,不等式符号应该是相反的。此外,对于孩子来说,它应该允许平等,因为同一年有两个孩子是可能的。 顺便说一句,我设法将我们的答案组合成一个只有三行正文的函数。不过看起来有点太疯狂了。 ;D
    猜你喜欢
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    相关资源
    最近更新 更多