当我在OCaml的树上对函数进行编程时,我总是会遇到这个反复出现的问题:当我到达树的叶子时,我什么也不想返回,但仍然希望我的编程继续进行。
为了更清楚一点,有时我有一些练习要求找到一个特定的节点 n ,所以我可以执行以下操作:(为简单起见,我在此处对二叉树进行此操作):
let rec find_node n tree = match tree with
|Nil -> (* I don't want my program to stop here but then what can I return ?*)
|Node(l, k, r) as t when k =n -> t
|Node(l, _, r) -> find_node n l; find_node n r
我正在使用以下表示的二叉树:
type b_tree = Nil | Node of b_tree * int * b_tree
所以基本上,我希望我的程序能够继续运行,直到找到所需的内容为止,但是由于OCaml中的一个函数只有一个返回类型,所以我无法做这样的事情:
let rec find_node n tree = match tree with
|Nil -> () (*returning unit type here*)
|Node(l, k, r) as t when k =n -> t
|Node(l, _, r) -> find_node n l; find_node n r
那么,如何识别模式案例中的“不执行任何操作”?
谢谢!
答案 0 :(得分:6)
您需要问自己:在第三种情况下,您如何知道第一次递归找到了结果?您如何将其与不成功的递归区分开来?在两种情况下该怎么办?另外,如果整个树中没有满足您条件的节点怎么办?
“什么都不做”不是您想要的,您需要以某种方式表明什么也没找到。
解决所有这些问题的一种明显方法是返回一个选项,这将产生以下代码:
let rec find_node n tree =
match tree with
| Nil -> None
| Node ((_, k, _) as t) when k = n -> Some t
| Node (l, _, r) ->
match find_node n l with
| None -> find_node n r
| some -> some
其返回类型为(b_tree * int * b_tree) option
,描述节点属性,或者为None
,表示未找到节点。
答案 1 :(得分:0)
There are two ways to look at this:
1) When you hit Nil
in find_node that means that no node was found. You have to return some form of nothing.
1a) You return None
, which also means you have to return Some x
in the other cases. This is the API flavor with options.
1b) You raise Not_found. This the the API flavor with exceptions.
Some modules follow 1a, other 1b. Some have submodules for the flavors or 2 functions e.g. find_node (exception) and find_node_opt (option). What flavor should you have? That's 50% personal preference and 50% use case. Both are equally valid and both have advantages on the other depending on the use case.
2) Your data type is to blame
I've seen trees defined as
type b_tree = Leaf of int | Node of b_tree * int * b_tree
That way you don't have a Nil case. On the other hand there is no representation of an empty tree then.