F# Recursive Tree Validation

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-08 03:32:52

问题


This is a somewhat beginner question. I have been trying to validate the following type of FamilyTree. I can't find a simple way to do this. All help would be appreciated.

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

I want to validate a given family tree such that every Person is older than their Children and furthermore check if the list of Children is sorted in order of their age (eldest first). Preferably done with a function that return a boolean. Something along the lines of this:

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

回答1:


I'd do something like this:

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

where minParentAge is set to a reasonable minimum age to have children at.

I'd expect checkAges to be the more difficult part here: the function checks whether the first child it sees is younger than the limit it is given, then recursively checks the next child, with the current child's age as the new limit.

Note some techniques:

  • The function that checks child ages takes the minimum birthday as input; this is used to validate that the parent is old enough for the first child to be reasonable.

  • List.forall checks a predicate for all items in a list, and early-outs if a predicate is not fulfilled

  • function is a shorthand to create a function that does pattern matching on its parameter. Therefore, checkAges actually has two arguments.




回答2:


Here's a very simple solution using a single recursive function. It's not relying on built-in functions like List.forall but I think it's very declarative and (hopefully) easy to follow.

  • Rule 1: Every Person is older than their Children
  • Rule 2: List of Children is sorted in order of their age (eldest first)

Code:

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

I personally don't feel List.forall fits well here, it helps to solve a part of the problem but not the whole, so you need to combine it with more stuff (see the other answers) and in the end you can't avoid a recursive function.

List functions are good for lists but for trees I feel recursion more natural unless your tree provides already a way to traverse it.




回答3:


Here's a way to do it. Perhaps spending some time analyzing how this works will be helpful to you.

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


来源:https://stackoverflow.com/questions/27154171/f-recursive-tree-validation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!