给出树的类型:
type id = int;;
type tree = T of id * tree list;;
let ex = T(12,[T(3,[T(4,[T(38,[])])]);T(23,[T(22,[])]);T(1,[])]);;
鉴于所有id都是唯一的,我想从给定的id中获取一棵树,如下所示:
get 23 ex = t(23, [t(22,[])]);
到目前为止,我只能制作这样的函数:
let rec child c n =
match c with
| [] -> []
| e::es -> (get n e) @ (child es n)
and get id t =
match t with
| T(id1,c) when id=id1-> [t]
| T(_,c) -> child c id;;
哪个好,但该函数完全贯穿树中的所有节点。是否有可能使函数在找到正确的节点时终止,从而跳过一些计算?
答案 0 :(得分:3)
您需要使递归调用返回一个值,该值以某种方式包含有关是否找到该节点的响应。如果确实如此 - 只需返回它,如果它没有 - 保持(递归地)搜索树的其余部分。
为此,F#有一个方便的内置类型 - Option
。它是一个定义为type Option<'t> = Some of 't | None
的和类型。所以我会让get
函数返回Option<tree>
而不是tree list
,然后child
函数可以决定是否要继续:
let rec child c n =
match c with
| [] -> None
| e::es -> match get n e with
| Some x -> Some x // node found - just return it
| None -> child es n // not found - keep searching
and get id t =
match t with
| T(id1,c) when id=id1-> Some t
| T(_,c) -> child c id;;
另请注意,您的child
功能实际上在标准库中以List.tryPick
的名称提供:
let rec child c n = List.tryPick (get n) c
这使得整个事情陷入了这个:
let rec get id t =
match t with
| T(id1,_) when id=id1 -> Some t
| T(_,c) -> List.tryPick (get id) c