When my brain hurts cuz it's stuck up a tree, I try to say what I want as simply and clearly as I can:
- Given a tree of info, list all sub-trees matching a predicate (in this case, info = 3).
One straightforward way to do it is to list all nodes of the tree, then filter on the predicate.
type 'info tree = Node of 'info * 'info tree list
let rec visit = function
| Node( info, [] ) as node -> [ node ]
| Node( info, children ) as node -> node :: List.collect visit children
let filter predicate tree =
visit tree
|> List.filter (fun (Node(info,_)) -> predicate info)
Here's the tree filter run against the OP's sample data:
let result = filter (fun info -> info = 3) test
One thing that surprised me is how easily the code works for any 'info type with the appropriate predicate:
let test2 =
Node(("One",
[Node("Two",
[Node("Three",[Node("Five",[]);Node("Three",[])]);
Node("Three",[])]);
Node("Three",[])]))
let res2 = filter (fun info -> info = "Three") test2
Alternatively, if you wanted to list the info rather than the sub-trees, the code is breath-takingly simple:
let rec visit = function
| Node( info, [] ) -> [ info ]
| Node( info, children ) -> info :: List.collect visit children
let filter predicate tree =
visit tree
|> List.filter predicate
which supports the same queries but only returns the 'info records, not the tree structure:
let result = filter (fun info -> info = 3) test
> val result : int list = [3; 3; 3; 3]